1. 程式人生 > 其它 >P2375 [NOI2014] 動物園

P2375 [NOI2014] 動物園

【題意】

求一個字串的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); } }