Counting the String 动态规划 + KMP

来源:互联网 发布:java写的程序怎么运行 编辑:程序博客网 时间:2024/05/29 19:49
/*    题目描述:给出一个长度为n(0 < n < 2e6)的字符串s,问其共有多少子串与s的任一前缀相等。        思路:假设字符串下标从1 ~ n ,dp[i]表示以i结尾的字串中包含前缀的个数,f[i]表示长度为i子串前后最大公共长度。                令p = f[i] , 则dp[i] = dp[p] + 1                这样转移的原因是以i结尾的前缀们一定包含在s[1...p]内,而s[1...p]内一切前缀皆为以i结尾的一个子串;                除此之外,以i结尾的还有子串s[1...i],所以要加一;                f数组的求解是KMP原理的精髓                    收获:前缀问题可能与KMP有联系*/#pragma warning(disable:4786)#pragma comment(linker, "/STACK:102400000,102400000")#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<stack>#include<queue>#include<map>#include<set>#include<vector>#include<cmath>#include<string>#include<sstream>#include<bitset>#define LL long long#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)#define mem(a,x) memset(a,x,sizeof(a))#define lson l,m,x<<1#define rson m+1,r,x<<1|1using namespace std;const int INF = 0x3f3f3f3f;const int mod = 10007;const double PI = acos(-1.0);const double eps=1e-6;const int maxn = 2e5 + 5;char s[maxn];int f[maxn];LL dp[maxn];void getFail(){    int m = strlen(s);    f[0] = 0;   f[1] = 0;    for(int i = 1 ; i<m ; i++){        int j = f[i];        while(j && s[i] != s[j])    j = f[j];        if(s[i] == s[j])    f[i + 1] = j + 1;        else        f[i + 1] = 0;    }}int main(){    int T , m;    scanf("%d", &T);    while(T--){        scanf("%d %s" , &m , s);        getFail();        LL ans = 0;        for(int i = 1 ; i<= m ; i++){            int p = f[i];            dp[i] = 1 + dp[p];            ans = (ans + dp[i]) % mod;        }        printf("%lld\n",ans);    }    return 0;}

0 0
原创粉丝点击