标签:
http://www.lydsy.com/JudgeOnline/problem.php?id=3670
对于一个字符串,求出num数组,其中num[i]表示前i个字符构成的字串中不相重合的相同前后缀共有多少对.
在做kmp的自匹配时,顺便记录一个cnt数组,其中cnt[i]表示第i个字符需要进行几次i=fail[i]到达0,也就是如果失配时跳转到i位置,包括i位置,之前共有多少可以作为失配时跳转对象的(也就是有多少满足和后面某一后缀相同的前缀).第二遍做子匹配时,将失配指针一直跳到小于等于i/2的位置j,此时cnt[j]就是共有多少满足的相同前缀后缀组即num[i].(手画画更清楚点?)
p.s.第二次匹配时如果i位置跳转到了k,那么k之后的任意数k‘都满足k‘>i/2,那么在i+1时,k‘+1>(i+1)/2,所以如果在i位置跳转到了k,在i+1位置继续从k+1位置即可.
#include <cstdio> const int mod=1e9+7; const int maxn=1e6+5; int ans; char c[maxn]; int fail[maxn],cnt[maxn]; void kmp(){ int j=0; fail[1]=0,cnt[1]=1; for(int i=2;c[i];i++){ while(j&&c[j+1]!=c[i]) j=fail[j]; if(c[i]==c[j+1]) j++; fail[i]=j; cnt[i]=cnt[j]+1; } j=0;ans=1; for(int i=2;c[i];i++){ while(j&&c[j+1]!=c[i]) j=fail[j]; if(c[i]==c[j+1]) j++; while((j<<1)>i) j=fail[j]; ans=((long long)ans*(long long)(cnt[j]+1))%mod; } } int main() { int n; scanf("%d",&n); while(n--){ scanf("%s",c+1); kmp(); printf("%d\n",ans); } return 0; }
标签:
原文地址:http://www.cnblogs.com/Sunnie69/p/5490178.html