BZOJ 3670: [Noi2014]动物园 [KMP]
2017-02-19 20:00
405 查看
求这玩意:
对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]
对1,000,000,007取模的结果
n≤5,L≤1,000,000
发现$num[i]$有和$fail[i]$类似的递增性质,$num[i]<num[i-1]+1$
然后$KMP$之后$fail$递推出$sum[i]$为$i$的$fail$祖先有几个
再类似求$fail$的过程求一遍$num$,只是多了判断$2*j \le i$,用$sum[j]$更新答案就行了
对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]
对1,000,000,007取模的结果
n≤5,L≤1,000,000
发现$num[i]$有和$fail[i]$类似的递增性质,$num[i]<num[i-1]+1$
然后$KMP$之后$fail$递推出$sum[i]$为$i$的$fail$祖先有几个
再类似求$fail$的过程求一遍$num$,只是多了判断$2*j \le i$,用$sum[j]$更新答案就行了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <bitset> using namespace std; typedef long long ll; const int N=1e6+5,MOD=1e9+7; int n; char s ; int fail ,sum ; void KMP(){ fail[1]=0; for(int i=2;i<=n;i++){ int j=fail[i-1]; while(j&&s[i]!=s[j+1]) j=fail[j]; fail[i]=s[i]==s[j+1]?j+1:0; } sum[0]=0; for(int i=1;i<=n;i++) sum[i]=sum[fail[i]]+1; //for(int i=1;i<=n;i++) printf("hi %d %d %d\n",i,fail[i],sum[i]); int j=0; ll ans=1; for(int i=2;i<=n;i++){ while(j&&s[i]!=s[j+1]) j=fail[j]; if(s[i]==s[j+1]) j++; while((j<<1)>i) j=fail[j];//printf("j %d\n",j); ans=ans*(sum[j]+1)%MOD; } printf("%lld\n",ans); } int main(){ freopen("in","r",stdin); int T;scanf("%d",&T); while(T--){ scanf("%s",s+1); n=strlen(s+1); KMP(); } }
相关文章推荐
- 【bzoj 3670】 [Noi2014]动物园 KMP变式
- [NOI2014][bzoj3670] 动物园 [kmp+next数组应用]
- BZOJ 3670: [Noi2014]动物园 KMP
- bzoj3670: [Noi2014]动物园 KMP
- 【BZOJ3670】【NOI2014】动物园 [KMP][倍增]
- BZOJ_3670_[NOI2014]_动物园_(kmp)
- [省选前题目整理][BZOJ 3670][NOI 2014]动物园(KMP)
- 【KMP,next树】BZOJ3670 [Noi2014]动物园
- 【KMP】[Noi2014] bzoj3670 动物园
- 【KMP】BZOJ3670-[Noi2014]动物园
- 字符串(KMP):BZOJ 3670 [Noi2014]动物园
- 【BZOJ3670】【NOI 2014】动物园(KMP)
- BZOJ_3670_[Noi2014]动物园_KMP
- BZOJ 3670([Noi2014]动物园-kmp变形)
- [NOI2014][BZOJ3670] 动物园|KMP
- BZOJ3670【NOI2014】动物园(KMP变形)
- bzoj 3670 [Noi2014]动物园【kmp】
- BZOJ3670 [Noi2014]动物园 【KMP计数】
- [bzoj 3670] NOI 2014 动物园 变形KMP
- [KMP next树] BZOJ 3670 [Noi2014]动物园