BZOJ 4327:[JSOI2012]玄武密码

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#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 @   ~Silent  阅读(152)  评论(0编辑  收藏  举报
Live2D
欢迎阅读『BZOJ 4327:[JSOI2012]玄武密码』
点击右上角即可分享
微信分享提示