codevs1040:统计单词个数
题目描述 Description
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)(管理员注:这里的不能再用指的是位置,不是字母本身。比如thisis可以算做包含2个is)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。
输入描述 Input Description
第一行为一个正整数(0<n<=5)表示有n组测试数据
每组的第一行有二个正整数(p,k)
p表示字串的行数;
k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)
接下来的s行,每行均有一个单词。
输出描述 Output Description
每行一个整数,分别对应每组测试数据的相应结果。
样例输入 Sample Input
1
1 3
thisisabookyouareaoh
4
is
a
ok
sab
样例输出 Sample Output
7
数据范围及提示 Data Size & Hint
this/isabookyoua/reaoh
题解
AC自动机+划分dp。。。有点长,不过思路挺明确。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<string> 5 #define maxn 150 6 using namespace std; 7 int tot,trie[maxn][30],fail[maxn],flg[maxn],q[maxn],wl[maxn]; 8 char str[30]; 9 string z; 10 int n,k,m; 11 int vis[205]; 12 int f[205][45],a[205][205]; 13 void insert(char *s) 14 { 15 int cnt(0); 16 int len = strlen(s); 17 int p = 0; 18 for(int i = 0 ; i < len; i ++) 19 { 20 int id = s[i] -'a'; 21 if(!trie[p][id]) p = trie[p][id] = ++tot; 22 else p = trie[p][id]; 23 ++cnt; 24 } 25 flg[p] = 1; 26 wl[p]=cnt; 27 } 28 29 void getfail() 30 { 31 int p = 0,Head = 0,Tail = 0; 32 q[++Tail] = p; 33 while(Head != Tail) 34 { 35 p = q[++Head]; 36 for(int i = 0 ; i < 26; i ++) 37 { 38 int x = trie[p][i]; 39 if(x) 40 { 41 fail[x] = p ? trie[fail[p]][i] :0; 42 q[++Tail] = x; 43 } 44 else trie[p][i] = trie[fail[p]][i]; 45 } 46 } 47 } 48 49 int match(int len) 50 { 51 int cnt(0); 52 int p = 0; 53 for(int i = 0 ; i <= len ; i ++) 54 { 55 int id = z[i] - 'a'; 56 p = trie[p][id]; 57 int t = p; 58 while(t) 59 { 60 if(flg[t]&&!vis[i-wl[t]+1]) 61 { 62 cnt++; 63 vis[i-wl[t]+1]=1; 64 } 65 t = fail[t]; 66 } 67 } 68 return cnt; 69 } 70 void init() 71 { 72 scanf("%d%d",&n,&k); 73 --k; 74 for(int i=1 ; i<=n ; ++i) 75 { 76 scanf("%s",str); 77 z+=str; 78 } 79 n=20*n-1; 80 scanf("%d",&m); 81 for(int i=1; i<=m ;++i) 82 { 83 scanf("%s",str); 84 insert(str); 85 } 86 getfail(); 87 for(int i=0 ;i<=n ; ++i) 88 { 89 for(int j=0;j<=i;++j)vis[j]=0; 90 f[i][0]=match(i); 91 a[0][i]=f[i][0]; 92 if(a[0][i]) 93 for(int j=1; j<=i ; ++j) 94 { 95 a[j][i]=a[j-1][i]-vis[j-1]; 96 if(!a[j][i])break; 97 } 98 } 99 } 100 void dp() 101 { 102 for(int p=1;p<=k;++p) 103 for(int i=p;i<=n;++i) 104 for(int j=p-1;j<i;++j) 105 f[i][p]=max(f[i][p],f[j][p-1]+a[j+1][i]); 106 printf("%d\n",f[n][k]); 107 } 108 void sta() 109 { 110 for(int i=0 ; i<=n ;++i) 111 { 112 for(int j=0 ; j<45 ; ++j) 113 f[i][j]=0; 114 for(int j=0 ; j<=n ; ++j) 115 a[i][j]=0; 116 } 117 for(int i=0; i<150 ; ++i) 118 { 119 fail[i]=flg[i]=wl[i]=q[i]=0; 120 for(int j=0;j<30;++j) 121 trie[i][j]=0; 122 } 123 tot=0; 124 z=""; 125 } 126 int main(){ 127 int T; 128 scanf("%d",&T); 129 while(T--) 130 { 131 init(); 132 dp(); 133 sta(); 134 } 135 return 0; 136 }