[NOI2014][洛谷P2375]动物园(KMP)
题面
https://www.luogu.com.cn/problem/P2375
题解
可以构建该字符串的一棵next树,即每个点向自己的next连一条边。
如果没有“不重叠”的限制条件,所求num[i]即为next树上点i的深度。
有该条件后,只需要维护位置mid,设当前dfs到点i,则mid为i到根路径上,<=i/2的最大者
所求num[i]即为dfs到i时对应mid的深度
mid全程移动的路程小于i全程移动的路程O(n)
代码
#include<bits/stdc++.h>
using namespace std;
#define N 1000000
#define ll long long
#define mod 1000000007
#define rg register
inline int read(){
int s = 0,ww = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
return s * ww;
}
int n,cnt;
char s[N+5];
int head[N+5],nx[N+5];
struct node{
int next,des;
}e[N+5];
inline void addedge(int a,int b){
cnt++;
e[cnt].des = b;
e[cnt].next = head[a];
head[a] = cnt;
}
inline void prepro(){
nx[1] = 0;
int p = 0;
for(rg int i = 2;i <= n;i++){
while(p && s[p+1] != s[i])p = nx[p];
if(s[p+1] == s[i])p++;
nx[i] = p;
}
}
int S[N+5],dep[N+5],num[N+5];
int top,mid;
inline void dfs(int u){
S[++top] = u;
if(u)while((S[mid+1]<<1) <= u)mid++;
num[u] = dep[S[mid]];
for(rg int i = head[u];i;i = e[i].next){
int v = e[i].des;
dep[v] = dep[u] + 1;
int temp = mid;
dfs(v);
mid = temp;
}
top--;
}
int main(){
int T = read();
while(T--){
memset(head,0,sizeof(head));
cnt = 0;
scanf("%s",s + 1);
n = strlen(s + 1);
prepro();
for(rg int i = 1;i <= n;i++)addedge(nx[i],i);
top = mid = 0;
dfs(0);
ll ans = 1;
for(rg int i = 1;i <= n;i++)ans = ans * (ll)(num[i] + 1) % mod;
cout << ans << endl;
}
return 0;
}