题目:https://www.luogu.org/problemnew/show/P1026
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成kk份(1<k \le 401<k≤40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。
对于字符串string函数处理:https://user.qzone.qq.com/1243296256/infocenter?_t_=0.8054686899343291
预处理一波单词个数以后就可以dp了
状态转移方程:
f[i][k]=max(f[i][k],f[j][k-1]+a[j+1][i]);
注意!!!
最后的循环要注意j>=0 ,也不能盲目max(0,k-2);会出错!!!
代码如下:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;
int p,k1,t,len;
string s,zd[10];
long long f[200+5][45],a[205][205];
int main()
{
int i,j,k;
string s1;
freopen("a.txt","r",stdin);
memset(f,0,sizeof(f));
memset(a,0,sizeof(a));
cin>>p>>k1;
s=""; len=20*p;
for (i=0;i<p;i++)
{
cin>>s1;
s=s+s1;
}
cin>>t;
for (i=0;i<t;i++)
cin>>zd[i];
// cout<<s.find("isa",0);
// cout<<s.substr(1,2);
// cout<<s;
for (j=len-1;j>=0;j--)
{
for (i=j;i>=0;i--)
{
s1=s.substr(i,j-i+1);
// if (i==0 && j==1)
// cout<<s1<<endl;
a[i][j]=a[i+1][j];
for (k=0;k<t;k++)
{
if (s1.find(zd[k],0)==0)
{
a[i][j]++;
break;
}
}
}
}
for (i=0;i<len;i++)
{
for (k=1;k<=min(i+1,k1);k++)
{
// if (i==199 && k==4)
// printf("zbk");
for (j=k-2;j<i;j++)
{
int j1=max(j,0);
f[i][k]=max(f[i][k],f[j1][k-1]+a[j+1][i]);
}
}
}
cout<<f[len-1][k1]<<endl;
return 0;
}