bzoj3670[Noi2014]动物园
题意:
对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]。给出字符串S求所有num[i]+1的乘积模1000000007。字符串长度≤1000000
题解:
先求一遍fail函数,得到数组记为next1,然后再求next2数组,表示满足next1[j]*2≤i的next1[j],这一过程也是可以递推的。同时用cnt数组记录next1[j]有多少个。num[i]就是cnt[next2[i]]。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 1000100 5 #define inc(i,j,k) for(int i=j;i<=k;i++) 6 #define mod 1000000007 7 using namespace std; 8 9 char s[maxn]; int next1[maxn],next2[maxn],cnt[maxn],t,len; long long ans; 10 int main(){ 11 scanf("%d",&t); 12 while(t--){ 13 scanf("%s",s+1); len=strlen(s+1); next1[1]=0; cnt[1]=1; next2[1]=0; 14 inc(i,2,len){ 15 int j=next1[i-1]; while(j&&s[j+1]!=s[i])j=next1[j]; 16 if(s[j+1]==s[i])next1[i]=j+1,cnt[i]=cnt[next1[i]]+1;else next1[i]=0,cnt[i]=1; 17 } 18 inc(i,2,len){ 19 int j=next2[i-1]; if(j*2+2>i)j=next1[j]; while(j&&s[j+1]!=s[i])j=next1[j]; 20 if(s[j+1]==s[i])next2[i]=j+1;else next2[i]=0; 21 } 22 ans=1; inc(i,1,len)ans=ans*(cnt[next2[i]]+1)%mod; printf("%lld\n",ans); 23 } 24 return 0; 25 }
20160806