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 }

 

 

 

posted @ 2017-09-18 23:36  傅judge  阅读(194)  评论(0编辑  收藏  举报