NOIP2001 统计单词个数 rabin-karp哈希

来源:互联网 发布:航天税控软件 编辑:程序博客网 时间:2024/06/13 06:44

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 3thisisabookyouareaoh4isaoksab

样例输出

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 1000000007ll 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;}


原创粉丝点击