NOIP200107统计单词个数
NOIP200107统计单词个数 |
难度级别: A; 编程语言:不限;运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B |
试题描述
|
给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠,但不能选出两个单词而它们的开始位置相同)。 单词在给出的一个不超过6个单词的字典中。要求输出最大的个数。 |
输入
|
第一行有两个正整数p和k
p表示字串的行数; k表示分为k个部分。 接下来的p行,每行均有20个字符。 再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6) 接下来的s行,每行均有一个单词。 |
输出
|
一个整数,对应每组测试数据的相应结果。
|
输入示例
|
1 3
thisisabookyouareaoh 4 is a ok sab |
输出示例
|
7
|
妈妈我发现自己原来写的hash都是错的233333333
对于每个位置,暴力与6个单词进行匹配,计算出区间[l,r]的单词数,然后DP即可。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define hash(x,l) H[x]-H[x+l]*xp[l] #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i!=-1;i=next[i]) using namespace std; inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } typedef unsigned long long ull; const int maxn=210; const int maxk=41; char s[7][maxn],S[maxn]; ull xp[maxn],H[maxn],hs[7]; int n,k,m,len,vis[7],length[7],w[maxn][maxn],vis2[1010]; int f[maxn][maxk]; int main() { int T=1; while(T--) { n=read();k=read();len=0; rep(i,1,n) { rep(j,1,20) S[++len]=getchar(); getchar(); } m=read(); rep(i,1,m) { scanf("%s",s[i]);length[i]=strlen(s[i]); dwn(j,length[i]-1,0) hs[i]=hs[i]*233+s[i][j]; } dwn(i,len,1) H[i]=H[i+1]*233+S[i]; xp[0]=1;rep(i,1,len) xp[i]=xp[i-1]*233; rep(l,1,len) rep(r,l,len) { int sum=0; rep(i,l,r) { int ok=0; rep(id,1,m) if(length[id]+i-1<=r) { if(hash(i,length[id])==hs[id]&&!ok) ok=1,sum++; } } w[l][r]=sum; } rep(i,1,len) f[i][1]=w[1][i]; rep(j,2,k) rep(i,j,len) { f[i][j]=0; rep(t,j-1,i-1) f[i][j]=max(f[i][j],f[t][j-1]+w[t+1][i]); } printf("%d\n",f[len][k]); } return 0; }