P2375 [NOI2014] 動物園
阿新 • • 發佈:2021-10-17
【題意】
求一個字串的num陣列,表示1-i的即使字首也是字尾且不重疊的串的個數
【分析】
考慮不斷跳nxt陣列,如nxt[i],nxt[nxt[i]]....
直到跳到長度小於i的一半的時候開始計數那麼就得到了num陣列
可是這樣做的最壞時間複雜度仍然是$O(n^2)$,繼續考慮優化,即減少重複遞迴
現在正常計算kmp時候順便遞推出ans陣列,表示可以重複的弱化num個數
然後對於每個位置,利用nxt陣列跳到可行的位置後,答案就為這個位置的ans值
【程式碼】
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll mod=1e9+7; const int maxn=1e6+6; int n,fail[maxn],ans[maxn]; ll cnt; char a[maxn]; int main() { freopen("zoo.in","r",stdin); freopen("zoo.out","w",stdout); int T; scanf("%d",&T); while(T--) { scanf("%s",a); n=strlen(a); int j=0; ans[0]=0;ans[1]=1; memset(fail,0,sizeof(fail)); for(int i=1;i<n;i++) { while(j && a[i]!=a[j]) j=fail[j]; if(a[i]==a[j]) j++; fail[i+1]=j; ans[i+1]=ans[j]+1; } // for(int i=1;i<n;i++) printf("%d ",ans[i]); j=0; cnt=1; for(int i=1;i<n;i++) { while(j && a[i]!=a[j] ) j=fail[j]; if(a[i]==a[j]) j++; while((j<<1)>(i+1)) j=fail[j]; cnt=(cnt*(ll)(ans[j]+1))%mod; } printf("%lld\n",cnt); } }