hdu3336 Count the string(next数组)

来源:互联网 发布:cip数据核字号在哪里 编辑:程序博客网 时间:2024/06/05 05:50

题目:

统计字符串s的所有前缀在s中的出现次数。

分析:

如果从正面考虑,枚举每个前缀然后找一遍,是O(n^2)的算法,不能接受。
这道题要倒着考虑,利用next数组的性质。任何一个next值都意味着两个相同的前缀和后缀,换句话说,所有的前缀都会在next数组中有所体现。next[i]表示一个以i结尾的既是前缀也是后缀的片段,next[next[i]]也是一个以i结尾的这样的片段,只不过长度更短,以此类推,一直这样下去,这个片段会越来越短,但是都是以第i个字符结尾的,直到next=0。这样我们就找到了所有以i结尾的,同样也是前缀的片段。那些不是前缀的片段不能再next数组中体现。所以用这样的方法,让1~n个字符都当做一次结尾,这样求一遍,就可以了。

代码:

#include <iostream>#include <algorithm>#include <queue>#include <stack>#include <vector>#include <map>#include <set>#include <cmath>#include <cstdlib>#include <cstring>#include <cstdio>using namespace std;#define ms(a,b) memset(a,b,sizeof(a))#define lson rt*2,l,(l+r)/2#define rson rt*2+1,(l+r)/2+1,rtypedef unsigned long long ull;typedef long long ll;const int MAXN=2e5+5;const double EPS=1e-8;const int INF=0x3f3f3f3f;const int MOD = 1e4+7;char s[MAXN];int n,nxt[MAXN];void getnext(){    nxt[0] = 0;    for(int i=1;i<n;i++){        int j = nxt[i-1];        while(s[j] != s[i] && j > 0)    j = nxt[j-1];        if(s[j] == s[i])    nxt[i] = j+ 1;        else    nxt[i] = 0;    }}int main(){    int T;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        scanf("%s",s);        getnext();        int ans = 0;        for(int i=n-1;i>=0;i--){            int j = nxt[i];            ans = (ans + 1) % MOD;            while(j > 0){                ans = (ans + 1) % MOD;                j = nxt[j-1];            }        }        printf("%d\n",ans);    }    return 0;}
原创粉丝点击