题目描述
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。
输入输出格式
输入格式:
每组的第一行有二个正整数(p,k)
p表示字串的行数;
k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)
接下来的s行,每行均有一个单词。
输出格式:
一个整数,分别对应每组测试数据的相应结果。
输入输出样例
说明
this/isabookyoua/reaoh
因为不太会处理字符串,但看到判断字符相等,哈希有大用处了。
分别把每一个子串哈希一遍和目标串匹配,匹配完成将这一段加1;
预处理出来一个map[i][j]表示在从i到j的区间里有合法的子串的个数.
那转移可以有以下,j为分的次数,i为当前分到第i个位置
··· dp[i][j]=max(dp[i][j],dp[1~i-1][j-1])
特殊的当j=1dp[i][1]=map[0][i]
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int Base=233,MOD=10000009;
char a[300],b[10][100];
int n,k,m,l[10],c[10],w[300][300];
int dp[300][300];
inline int ha(char b[],int len)
{
int i;
int val=0;
f(i,1,len){
val=(val*Base+b[i-1])%MOD;
}
return val;
}
inline int pd(int x,int y)
{
int i;
char tmp[15];
f(i,1,m){
if(y-x+1<l[i]) continue;
strncpy(tmp,a+x,l[i]);
if(ha(tmp,l[i])==c[i]) return 1;
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
int i,j,len,t;
cin>>n>>k;
f(i,1,n){
cin>>a+(i*20-20);
}
len=strlen(a);
cin>>m;
f(i,1,m){
cin>>b[i];
l[i]=strlen(b[i]);
c[i]=ha(b[i],l[i]);
}
ff(j,len-1,0){
ff(i,j,0){
w[i][j]+=w[i+1][j];
// if(i==5&&j==7) cout<<pd(i,j)<<"GG";
if(pd(i,j)) w[i][j]++;
}
}
f(i,0,len-1){
f(j,i,len-1){
// cout<<i+1<<' '<<j+1<<' '<<w[i][j]<<endl;
}
}
f(i,0,len-1){
f(j,1,k){
if(j==1) dp[i][j]=w[0][i];
else{
f(t,j-1,i-1){
// if(dp[t][j-1])
dp[i][j]=max(dp[i][j],dp[t][j-1]+w[t+1][i]);
}
}
}
}
cout<<dp[len-1][k]<<endl;
return 0;
}