NOI2014 动物园题解
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;
}