BZOJ 4327:[JSOI2012]玄武密码

对于询问串建AC自动机,用母串匹配,标记访问过的节点不再被访问,最后枚举每个串统计答案

#include<cstdio>
#include<cstring>
using namespace std;
int cnt,tree[10000005][5],a[10000005],len[100005],Fail[10000005],vis[10000005],q[10000005];
char s[10000005],S[100005][105];
void update(int x){
	for (int i=0; i<4; i++)
		if (!tree[x][i]) tree[x][i]=tree[Fail[x]][i];
}
void ac_(){
	int head=0,tail=0;
	vis[0]=1;
	for (int i=0; i<4; i++)
		if (tree[0][i]){
			update(tree[0][i]);
			q[++tail]=tree[0][i];
			vis[tree[0][i]]=1;
		}
	while (head<tail){
		int x=q[++head];
		for (int i=0; i<4; i++){
			int V=tree[x][i];
			if (vis[V]) continue;
			Fail[V]=tree[Fail[x]][i];
			update(V);
			vis[V]=1;
			q[++tail]=V;
		}
	}
}
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	scanf("%s",s+1);
	for (int i=1; i<=n; i++){
		if (s[i]=='E') a[i]=0;
		else if (s[i]=='S') a[i]=1;
		else if (s[i]=='W') a[i]=2;
		else a[i]=3;
	}
	for (int i=1; i<=m; i++){
		scanf("%s",S[i]+1);
		len[i]=strlen(S[i]+1);
		int now=0;
		for (int j=1; j<=len[i]; j++){
			int x;
			if (S[i][j]=='E') x=0;
			else if (S[i][j]=='S') x=1;
			else if (S[i][j]=='W') x=2;
			else x=3;
			if (!tree[now][x]) tree[now][x]=++cnt;
			now=tree[now][x];
		}
//		sz[now]=1;
	}
	ac_();
//	printf("%d\n",tree[1][3]);
	memset(vis,0,sizeof(vis));
	int now=0;
	for (int i=1; i<=n; i++){
		now=tree[now][a[i]];
//		printf("%d ",now);
		if (!vis[now]){
			int Pre=now;
			vis[Pre]=1;
			Pre=Fail[Pre];
			while (!vis[Pre]){
				vis[Pre]=1;
				Pre=Fail[Pre];
			}
		}
	}
//	printf("\n");
	for (int i=1; i<=m; i++){
		int now=0,maxlen=0;
		for (int j=1; j<=len[i]; j++){
			int x;
			if (S[i][j]=='E') x=0;
			else if (S[i][j]=='S') x=1;
			else if (S[i][j]=='W') x=2;
			else x=3;
			now=tree[now][x];
			if (!vis[now]) break;
			maxlen=j;
		}
		printf("%d\n",maxlen);
	}
	return 0;
}

  

posted @ 2018-10-16 18:32  ~Silent  阅读(149)  评论(0编辑  收藏  举报
Live2D