1233: NOIP2001:统计单词个数
时间限制: 0 Sec 内存限制: 128 MB提交: 8 解决: 6
[上一题][提交][讨论版][状态][下一题]
题目描述
给出一个长度不超过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行,每行均有一个单词。
输出
输出一个整数,即最大的个数
样例输入
1 3
thisisabookyouareaoh
4
is
a
ok
sab
样例输出
7
提示
NOIP2001提高组第三题
我用的是主流dp,所以这里不讲dp, 讲如何处理字符串。
我用的是rabin-karp哈希
记前 i 位的哈希值 为 hx[i]
搞一个base, 我的是131
hx[i] = (hx[i-1] * base + s[i]) % mod P
P是个大素数, 我选的是1e9+7
这样我们的hx[i]就等于 s[1]*base^i-1 + s[2]*base^i-2 + ..... s[i]*base^0
我们要求l, r的哈希值, 观察一下hx[l-1] 和 hx[r]
hx[l-1] = s[1]*base^l-2 + s[2]*base^l-3 + .....s[l-1]*base^0
hx[r] = s[1]*base^r-1 + s[2]*base^r-2 + .....s[r]*base^0
我们只看s[1]的指数就行了(后面一样的)
于是我们将hx[l-1]乘上 base^r-l+1次方, 用hx[r]一减, 从s[1]到s[l-1]的值全被消掉了
我们就得到了 [l, r]的哈希值
然后就dp就行了
dp也有一个坑的地方, 因为一定要分成k份, 不能 < k份, 所以我们在 f[t][j-1] 有值的时候才转移
代码如下:
#include <cstdio>
#include <string.h>
#define ll long long
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define base 131
#define mod 1000000007
ll hx[205], re[205], po[205], t, hav[205][205], s, l[7];
int f[205][205];
char a[205], b[25], c[1005];
int len;
ll gethash(int l, int r){
return ((hx[r] - po[r-l+1]*hx[l-1])%mod+mod) % mod;
}
int get(int x, int y){
int i;
for(i = 1; i <= s; i++) if(gethash(x, min(y, x+l[i]-1)) == re[i]) return 1;
return 0;
}
int main(){
int i, j, p, k, n;
scanf("%d%d", &p, &k);
scanf("%s", a+1);
len = strlen(a+1);
for(i = 2; i <= p; i++){
scanf("%s", b+1);
n = strlen(b+1);
for(j = len+1; j <= len+n; j++) a[j] = b[j-len];
len += n;
}
for(i = po[0] = 1; i <= len; i++){
po[i] = po[i-1] * base % mod;
hx[i] = (hx[i-1] * base + a[i]) % mod;
}
scanf("%d", &s);
for(i = 1; i <= s; i++){
scanf("%s", c+1);
n = strlen(c+1);
l[i] = n;
t = 0;
for(j = 1; j <= n; j++) t = (t * base + c[j]) % mod;
re[i] = t;
}
for(i = len; i >= 1; i--){
for(j = i; j >= 1; j--){
hav[j][i] = hav[j+1][i];
hav[j][i] += get(j, i);
}
}
for(i = 1; i <= len; i++){
f[i][1] = hav[1][i];
for(j = 2; j <= k; j++){
for(t = 1; t < i; t++){
if(f[t][j-1]) f[i][j] = max(f[i][j], f[t][j-1] + hav[t+1][i]);
}
}
}
printf("%d", f[len][k]);
return 0;
}