[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;
}
原文地址:https://www.cnblogs.com/xh092113/p/12239694.html