NOI2014 動物園題解
阿新 • • 發佈:2020-11-18
2種解法, SB O(nlogn) 和 SB O(n) 。聽到過另一種牛逼 O(n), 感覺有點假就沒寫。
SB O(n log n), 首先都知道 nxt 的指向關係可以構成一顆內向樹, 隨便二分一下就行了。
//sb O(n log n) #include<bits/stdc++.h> using namespace std; const int N = 1000003, mo = 1e9+7; int n; char s[N]; int ecnt, hd[N]; struct edge{int v,nt; } e[N]; void ad(int x,int y) { e[++ecnt] = (edge){y, hd[x]}; hd[x] = ecnt; } int nxt[N]; long long ans; int sta[N]; void dfs(int x,int fa,int d) { if(x>=2) { int l=0, r=*sta; while(l!=r) { int mid = (l+r+1) >> 1; if(sta[mid]<=x/2) l=mid; else r=mid-1; } ans = ans*(l+1ll) % mo; } if(x) sta[++*sta] = x; for(int i=hd[x],y=e[i].v; i; i=e[i].nt,y=e[i].v) if(y!=fa) dfs(y,x,d+1); --*sta; } int main() { int T; cin>>T; while(T--) { scanf("%s",s+1); n = strlen(s+1); for(int i=2,j=0; i<=n; ++i) { while(j && s[i]!=s[j+1]) j=nxt[j]; if(s[i] == s[j+1]) ++j; nxt[i]=j; } // input ecnt = 0; for(int i=0;i<=n;++i) hd[i]=0; for(int i=1;i<=n;++i) ad(nxt[i],i); *sta = 0; ans = 1ll; dfs(0,0,0); cout << ans << '\n'; } return 0; }
雖然比較 sb , 但這個做法這個是 O(n) 的, 思路來源於暴跳 nxt, 發現 i-1 的超過 \(\lfloor\dfrac{i-1}{2}\rfloor\) 的 Border 不可能通過加一個字元成為 i 的不超過 \(\lfloor\dfrac{i-1}{2}\rfloor\) 的 Border, 所以再開個 nxt2 陣列記錄最長的不超過 \(\lfloor\dfrac{i-1}{2}\rfloor\) 的 Border, 隨便搞搞就行了, 複雜度和經典 kmp 的複雜度一樣分析, 是均攤 O(n) 的。
// sb O(n) #include<bits/stdc++.h> using namespace std; #define li long long const int maxn = 1e6+5; const int mod = 1000000007; int len, nxx[maxn], nxt[maxn]; char s[maxn]; int dep[maxn]; int main() { int n; cin>>n; while(n--) { scanf("%s", s+1); len=strlen(s+1); for(int i=2,j=0,k=0;i<=len;++i) { while(j&&s[j+1]!=s[i]) j=nxt[j]; if(s[j+1]==s[i]) ++j; nxt[i]=j; while(k+1>i/2) k=nxt[k]; while(k&&s[k+1]!=s[i]) k=nxt[k]; if(s[k+1]==s[i]) ++k; nxx[i] = k; } dep[0] = 1; for(int i=1;i<=len;++i) dep[i]=dep[nxt[i]]+1; li ans = 1ll; for(int i=1;i<=len;++i) ans = 1ll*ans*dep[nxx[i]]%mod; cout<<ans<<'\n'; } return 0; }