Description
已知一个字符串S,对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]。
求mod 10^9+7。
Input
第1行仅包含一个正整数n,表示测试数据的组数。随后n行,每行描述一组测试数据。每组测试数据仅含有一个字符串S,S的定义详见题目描述。数据保证S中仅含小写字母。输入文件中不会包含多余的空行,行末不会存在多余的空格。
Output
包含n行,每行描述一组测试数据的答案,答案的顺序应与输入数据的顺序保持一致。对于每组测试数据,仅需要输出一个整数,表示这组测试数据的答案mod 10^9+7的结果。
Sample Input
3
aaaaa
ab
abcababc
Sample Output
36
1
32
Solution
题意就是给你一个字符串S,对于这个字符串S的每一个前缀S[1...i]的next[j]满足j*2<=i的个数记作num[i],求num[i]。
那么,就先思考问题的简化版,在没有j*2<=i的限制下,num[i]=num[next[i]]+1,将这种情况下的num[]记作cnt[]。
现在问题就变成了,如何不用O(n^2)的算法求满足条件的j。
我们可以再用kmp的思想完成这件事,当发现现在的j不满足条件时,可以用next[]向前寻找满足条件的j。
这样的话,每次都是从满足j*2<=i-1的j开始寻找,避免了一些重复向前找的时间复杂度,于是就A了。
1 #include<set> 2 #include<cmath> 3 #include<ctime> 4 #include<queue> 5 #include<stack> 6 #include<cstdio> 7 #include<vector> 8 #include<string> 9 #include<cstring> 10 #include<cstdlib> 11 #include<iostream> 12 #include<algorithm> 13 #define N 1000002 14 #define M 1000000007 15 using namespace std; 16 int t[N],cnt[N],next[N],n,m; 17 long long ans; 18 char a[N]; 19 inline void get_next(){ 20 for(int i=2,j=0;i<=m;i++){ 21 while(j&&a[i]!=a[j+1]) j=next[j]; 22 j+=(a[i]==a[j+1]); 23 next[i]=j; 24 cnt[i]=cnt[j]+1; 25 } 26 } 27 inline void init(){ 28 scanf("%d",&n);cnt[1]=1; 29 for(int l=1;l<=n;l++){ 30 scanf("%s",a+1); 31 m=strlen(a+1); 32 fill(next+1,next+1+m,0); 33 get_next();ans=1; 34 for(int i=2,j=0;i<=m;i++){ 35 while(j&&a[i]!=a[j+1]) j=next[j]; 36 if(a[i]==a[j+1]) j++; 37 while(j*2>i) j=next[j]; 38 ans=ans*(cnt[j]+1)%M; 39 } 40 printf("%lld\n",ans); 41 } 42 43 } 44 int main(){ 45 freopen("zoo.in","r",stdin); 46 freopen("zoo.out","w",stdout); 47 init(); 48 fclose(stdin); 49 fclose(stdout); 50 return 0; 51 }
时间: 2024-08-09 21:45:55