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; }