首页 > 其他分享 >[JSOI2012]玄武密码

[JSOI2012]玄武密码

时间:2022-09-24 16:46:22浏览次数:52  
标签:JSOI2012 ss 玄武 pp ac 密码 字串 include

题目

对于每一段文字 tt,求出其最长的前缀 pp,满足 pp 是 ss 的子串,其中ss是字串。

题解

我们可以用ac自动机来做,先把所有字串建个ac自动机,然后用母串在上面跑,把那些点都进行标记,最后dfs一次就好

code

点击查看代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=1e7+5;
const int M=1e6+5;//
char s[N],tt[105];
int ch[M][4],cnt,b[M],ch1[M][4],n,m,c,h,t,now,l,tot,val[N],r,u,v,f[N],last[N];
int sum[M];
int q[M],ans[M];
int G(char x){
	if (x=='E') return 0;
	if (x=='S') return 1;
	if (x=='W') return 2;
	if (x=='N') return 3;
}
void ins(int x){
	now=0;  
	fo(i,1,l){
		c=G(tt[i]);
		if (!ch[now][c]) ch[now][c]=++tot;
		ch1[now][c]=ch[now][c];
		
		now=ch[now][c];
	}
	b[x]=now;
}
void build(){
	h=t=0;
	fo(i,0,3) if (ch[0][i]) q[++t]=ch[0][i];
	while (h<t){
		r=q[++h];
		fo(i,0,3){
			u=ch[r][i];
			if (!u){
				ch[r][i]=ch[f[r]][i]; continue;
			}
			v=f[r];
			while (v && !ch[v][i]) v=f[v];
			f[u]=ch[v][i];
//			last[u]=val[f[u]] ? f[u]:last[f[u]];
			q[++t]=u;
		}
	}
}
void match(){
	now=0;
	fo(i,1,n){
		c=G(s[i]);
		u=ch[now][c];
		sum[u]++;
		while (f[u]) {
			sum[f[u]]++;
			u=f[u];
		}
		now=ch[now][c];
	}
}
void dfs(int x,int d,int z){
	if (sum[x]) ans[x]=d;
	else ans[x]=z;
	fo(i,0,3){
		if (ch1[x][i]) {
			if (sum[x]) dfs(ch1[x][i],d+1,d);
			else dfs(ch1[x][i],d+1,z);
		}
	}	 
}
int main(){
//	freopen("data.in","r",stdin);
	scanf("%d %d",&n,&m);
	scanf("%s",s+1);
	fo(i,1,m) {
		scanf("%s",tt+1);
		l=strlen(tt+1);
		ins(i);
	}
	
	build();
	match();
	
	dfs(0,0,0);
	fo(i,1,m) {
		printf("%d\n",ans[b[i]]);
	}
	return 0;
}

标签:JSOI2012,ss,玄武,pp,ac,密码,字串,include
From: https://www.cnblogs.com/ganking/p/16725918.html

相关文章