题目描述
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k≤40),
且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。
输入输出格式
输入格式:
每组的第一行有2个正整数(p,k)
p表示字串的行数,k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有1个正整数s,表示字典中单词个数。(1≤s≤6)
接下来的s行,每行均有1个单词。
输出格式:
1个整数,分别对应每组测试数据的相应结果。
完蛋了
想的DP方程太复杂了,根本没法写
完蛋惹
这里大致就是f[i][j]表示前i个字符,已经有了j个划分(不是分割线)
用aft[i]表示i往后,以i开头的单词最短到哪里
这样统计i到j的单词个数只要找到i到j中aft小于等于j的就可以了
这样首字母的问题,也很好的解决了
然后这里j是到了第几个分块,而不是第几个分割线(我的,复杂)这样直接枚举前一个分块的末端就可以了
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 const int maxn=207; 8 const int INF=0x7f7f7f7f; 9 int P,K,s,n,ans; 10 char a[maxn],wrd[7][maxn]; 11 int len[7],aft[maxn],f[maxn][maxn],map[maxn][maxn]; 12 bool vis[maxn]; 13 int main(){ 14 //freopen("a.in","r",stdin); 15 memset(f,-INF,sizeof(f)); 16 cin>>P>>K;memset(aft,INF,sizeof(aft)); 17 for(int i=1;i<=P;i++) 18 for(int j=1;j<=20;j++) 19 cin>>a[++n]; 20 cin>>s; 21 for(int i=1;i<=s;i++){ 22 scanf("%s",wrd[i]+1); 23 len[i]=strlen(wrd[i]+1); 24 } 25 for(int u=1;u<=n;u++){ 26 for(int i=1;i<=s;i++){ 27 int v=u+len[i]-1;bool flag=true; 28 for(int k=u;k<=v;k++){ 29 if(a[k]!=wrd[i][k-u+1]) { 30 flag=false;break; 31 } 32 } 33 if(flag) aft[u]=min(aft[u],v); 34 } 35 } 36 f[0][0]=0; 37 for(int i=1;i<=n;i++){ 38 for(int j=i+1;j<=n;j++){ 39 for(int k=i;k<=j;k++){ 40 if(aft[k]<=j) map[i][j]++; 41 } 42 } 43 } 44 for(int i=1;i<=n;i++){ 45 for(int j=1;j<=K;j++){ 46 for(int k=0;k<i;k++){ 47 f[i][j]=max(f[i][j],f[k][j-1]+map[k+1][i]); 48 } 49 } 50 } 51 /*for(int i=1;i<=n;i++){ 52 for(int j=0;j<i;j++){ 53 for(int k=1;k<=K;k++) 54 f[i][k]=max(f[i][k],f[j][k-1]+map[j+1][i]); 55 } 56 } */ 57 cout<<f[n][K]<<endl; 58 return 0; 59 }
真难过
今天下午的状态太不应该了