[NOI2014]动物园 题解(预览)

一开始读错题了淦。


对于一个位置 \(i\)\(num[i]\) 显然是满足条件的最大前缀长 \(k\)\(next[k]\) 跳到 \(0\) 需要的次数。

对每个 \(i\) 如何求 \(k\)? 类比 \(next\) 的递推方式, 只需要加个限制长度的 \(while\) 语句就可以求出 \(k\) 了。(\(i\)\(k\)\(i-1\)\(k\) 推出即可,至于为什么,画一画qwq)

如何计数一个位置 \(s\)\(nxt\) 跳到 \(0\) 的次数?可以发现若对于每个 \(s\),将 \(nxt[s]\)\(s\) 连一条有向边, 所形成的结构就是一棵树, 其中, 入度为 \(0\) 的节点为 \(0\), 且 \(s\)\(nxt\) 跳到 \(0\) 需要跳的次数就是以 \(0\) 为根时 \(s\) 的深度。


luogu数据AC代码

#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 ct, hed[maxn], nx[maxn<<1], ver[maxn<<1];
void ad(int a,int b) {
	ver[++ct] = b;
	nx[ct] = hed[a];
	hed[a] = ct;
}
int dep[maxn];
void dfs(int x,int Dep) {
	dep[x]=Dep;
	for(int i=hed[x];i;i=nx[i]) {
		int y=ver[i];
		dfs(y,Dep+1);
	}
}

int main()
{
	int n; cin>>n; while(n--) {
		ct = 0;
		memset(hed,0,sizeof hed);
		scanf("%s", s+1); len=strlen(s+1);
		nxt[1]=0;
		for(int i=2,j=0;i<=len;++i) {
			while(j&&s[j+1]!=s[i]) j=nxt[j];
			if(s[j+1]==s[i]) ++j;
			nxt[i]=j;
		}
		nxx[1]=0;
		for(int i=2,j=0;i<=len;++i) {
			while(j+1>i/2) j=nxt[j];
			while(j&&s[j+1]!=s[i]) j=nxt[j];
			if(s[j+1]==s[i]) ++j;
			nxx[i]=j;
		}
		//
		for(int i=1;i<=len;++i) ad(nxt[i],i);
		dfs(0,1);
		li ans = 1ll;
		for(int i=1;i<=len;++i) ans = ans*1ll*dep[nxx[i]]%mod;
		cout<<ans<<'\n';
	}
	return 0;
}
posted @ 2020-04-29 08:27  xwmwr  阅读(195)  评论(2编辑  收藏  举报