[HDU 3336]Count the String[kmp][DP]

来源:互联网 发布:大唐软件 编辑:程序博客网 时间:2024/05/01 10:51

题意:

求一个字符串的所有前缀串的匹配次数之和.

思路:

首先仔细思考: 前缀串匹配.

n个位置, 以每一个位置为结尾, 就可以得到对应的一个前缀串.

对于一个前缀串, 我们需要计算它的匹配次数.

k = next [ j ]

表示前缀串 Sj 的范围内(可以视为较小规模的子问题), 前缀串 Sk 是最长的&能够匹配两次的前缀串.

这和我们需要的答案有什么关系呢?

题目是求所有前缀串的匹配次数之和, 那么可以先求前缀串 Si 在整个串中的匹配次数, 再加和.


到此, 用到了两个"分治", 一是将大规模的问题减小为小规模的问题, 二是将询问的最终结果拆分成一个个步骤, 则专注于分析核心步骤.


可设dp[ i ]为前缀串 Si 在总串中出现的次数.

dp[i] = 1;

dp[next[i]] += dp[i];


#include <cstring>#include <cstdio>const int MAXN = 200005;const int MOD = 10007;int dp[MAXN],next[MAXN];char s[MAXN];//46MS1960Kvoid prekmp(){    next[0] = -1;    int j = -1;    for(int i=1;s[i];i++)    {        while(j!=-1 && s[j+1]!=s[i])    j = next[j];        if(s[j+1]==s[i])    j++;        next[i] = j;    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        int n;        scanf("%d",&n);        scanf("%s",s);        prekmp();        for(int i=0;i<n;i++)    dp[i] = 1;        dp[n] = 0;        for(int i=n-1;i;i--)        {            if(next[i]!=-1) {dp[next[i]] += dp[i];dp[next[i]] %= MOD;}        }        for(int i=0;i<n;i++)    {dp[n] += dp[i];dp[n] %= MOD;}        printf("%d\n",dp[n]);    }}

还有另一种思路:

可以将前缀的匹配次数视为包含的前缀个数.

最终的问题是求s中 (设每一种前缀i包含的前缀个数Fi ) ΣFi .

dp[i]为前缀串s[0...i]包含的前缀个数的新增数目(相对于前缀串s[0...i-1]).

dp[i] = dp[next[i]] + 1;//1表示它本身也是新增的一个前缀

#include <cstring>#include <cstdio>const int MAXN = 200005;const int MOD = 10007;int dp[MAXN],next[MAXN];char s[MAXN];//62MS1960Kvoid prekmp(){    next[0] = -1;    int j = -1;    for(int i=1;s[i];i++)    {        while(j!=-1 && s[j+1]!=s[i])    j = next[j];        if(s[j+1]==s[i])    j++;        next[i] = j;    }}int main(){    int T;    scanf("%d",&T);    while(T--)    {        int n;        scanf("%d",&n);        scanf("%s",s);        prekmp();        memset(dp,0,sizeof(int)*(n+1));        for(int i=0;i<n;i++)        {            if(next[i]!=-1)            {                dp[i] = dp[next[i]]+1;                dp[i] %= MOD;            }            else                dp[i] = 1;        }        for(int i=0;i<n;i++)    {dp[n] += dp[i];dp[n] %= MOD;}        printf("%d\n",dp[n]);    }}


原创粉丝点击