0%

AC自动机

Recently Peter received m strings as a birthday gift. These strings only consist of lowercase letters. But Peter is not happy, as he hates all of these strings. So he wants to construct a new string of length n and it cannot contain any of the m strings as a substring. Of course,the new string is made up of lowercase letters too. Now he wonders how many strings he can construct. Input On the first line there is only one integer T(T is about 10), representing the number of cases. In each case: there are two integers n, m(n ≤ 1000, m ≤ 50) on the first line followed by m lines, representing the m strings Peter received. Note that the total length of the m strings won’t exceed 500 in each case. Output For each test case, output an integer in one line, which is the number of strings Peter can construct mod 1000000007. Sample Input 1 5 1 aaa Sample Output 11879400

今天集训时候这道题因为不会AC自动机...就没做出来...跌了一大段Rating 其实就是在AC自动机上跑DP,唯一的坑点就是,如果一个点的fail是匹配的话,那这个点也是一个匹配...不过一个好的模板这个情况应该已经考虑到了... 剩下就很简单了...

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
#define mod 1000000007
using namespace std;
struct Trie
{
int next[500010][26],fail[500010],end[500010];
int root,L;
int newcode()
{
for(int i=0;i<26;i++)
next[L][i]=-1;
end[L++]=0;
return L-1;
}
void init()
{
L=0;
root=newcode();
}
void insert(char *s)
{
int len=strlen(s);
int now=root;
for(int i=0;i<len;i++)
{
if(next[now][s[i]-'a']==-1)
next[now][s[i]-'a']=newcode();
now=next[now][s[i]-'a'];
}
end[now]++;
}
void build()
{
queue<int> Q;
        fail[root] = root;
        for(int i=0;i<26;i++)
        {
            if(next[root][i]==-1)
                next[root][i]=root;
            else
            {
                fail[next[root][i]]=root;
                Q.push(next[root][i]);
            }
        }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i=0;i<26;i++)
            {
                if(next[now][i]==-1)
                {
                    next[now][i]=next[fail[now]][i];
                }
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    end[next[now][i]]|=end[fail[next[now][i]]];
                    Q.push(next[now][i]);
                }
            }
        }
}
int query(int n)
{
int now=root;
int f[2][250010]={};
f[0][now]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<=L;j++)
{
for(int k=0;k<26;k++)
{
if(end[next[j][k]]==0) f[(i+1)%2][next[j][k]]+=f[i%2][j];
f[(i+1)%2][next[j][k]]%=mod;
}
f[i%2][j]=0;
}
}
int res=0;
for(int j=0;j<=L;j++)
{
res+=f[n%2][j];
res%=mod;
}
return res;
}
void debug()
    {
        for(int i = 0;i < L;i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }
} tr;
void work()
{
tr.init();
int n,m;
char s[510];
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%s",s);
tr.insert(s);
}
tr.build();
printf("%d\n",tr.query(n));
}
int main()
{
int T;
scanf("%d",&T);
while(T--) work();
return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=2222 学习的时候刷了一道杭电oj的模板题

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
struct Trie
{
    int next[500010][26],fail[500010],end[500010];
    int root,L;
    int newcode()
    {
        for(int i=0;i<26;i++)
            next[L][i]=-1;
        end[L++]=0;
        return L-1;
    }
    void init()
    {
        L=0;
        root=newcode();
    }
    void insert(char *s)
    {
        int len=strlen(s);
        int now=root;
        for(int i=0;i<len;i++)
        {
            if(next[now][s[i]-'a']==-1)
                next[now][s[i]-'a']=newcode();
            now=next[now][s[i]-'a'];
        }
        end[now]++;
    }
    void build()
    {
        queue<int> Q;
        fail[root] = root;
        for(int i=0;i<26;i++)
        {
            if(next[root][i]==-1)
                next[root][i]=root;
            else
            {
                fail[next[root][i]]=root;
                Q.push(next[root][i]);
            }
        }
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            for(int i=0;i<26;i++)
            {
                if(next[now][i]==-1)
                {
                    next[now][i]=next[fail[now]][i];
                }
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    Q.push(next[now][i]);
                }
            }
        }
    }
    int query(char* s)
    {
        int len=strlen(s);
        int now=root;
        int res=0;
        for(int i=0;i<len;i++)
        {
            now=next[now][s[i]-'a'];
            int temp=now;
            while(temp!=root)
            {
                res+=end[temp];
                end[temp]=0;
                temp=fail[temp];
            }
        }
        return res;
    }
    void debug()
    {
        for(int i = 0;i < L;i++)
        {
            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);
            for(int j = 0;j < 26;j++)
                printf("%2d",next[i][j]);
            printf("]\n");
        }
    }
} tr;
void work()
{
    tr.init();
    int n;
    char s[1000010];
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s);
        tr.insert(s);
    }
    tr.build();
    scanf("%s",s);
    printf("%d\n",tr.query(s));
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--) work();
    return 0;
}

http://www.lydsy.com/JudgeOnline/problem.php?id=1030 f[i][j][0]代表长度为i,在自动机上编号j的位置,在之前没有匹配到的单词的情况数。 f[i][j][1]代表长度为i,在自动机上编号j的位置,在之前已经匹配过单词的情况数。

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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include<bits/stdc++.h>
#define mod 10007
using namespace std;
int n,m;
char s[110]={};
int f[110][6010][2]={};
struct Trie
{
int next[6010][26],fail[6010],end[6010];
int root,L;
int newcode()
{
for(int i=0;i<26;i++)
{
next[L][i]=-1;
}
end[L++]=0;
return L-1;
}
void init()
{
L=0;
root=newcode();
}
void insert(char *s)
{
int len=strlen(s);
int now=root;
for(int i=0;i<len;i++)
{
if(next[now][s[i]-'A']==-1)
{
next[now][s[i]-'A']=newcode();
}
now=next[now][s[i]-'A'];
}
end[now]++;
}
void build()
{
queue<int> Q;
fail[root]=root;
for(int i=0;i<26;i++)
{
if(next[root][i]==-1)
{
next[root][i]=root;
}
else
{
fail[next[root][i]]=root;
Q.push(next[root][i]);
}
}
while(!Q.empty())
{
int now=Q.front();
Q.pop();
for(int i=0;i<26;i++)
{
if(next[now][i]==-1)
{
next[now][i]=next[fail[now]][i];
}
else
{
fail[next[now][i]]=next[fail[now]][i];
end[next[now][i]]|=end[fail[next[now][i]]];
Q.push(next[now][i]);
}
}
}
}
int query(int m)
{
f[0][root][0]=1;
for (int i=0;i<m;i++)
{
for(int j=0;j<L;j++)
{
for(int k=0;k<26;k++)
{
f[i+1][next[j][k]][0]+=f[i][j][0];
f[i+1][next[j][k]][0]%=mod;
f[i+1][next[j][k]][1]+=f[i][j][1];
f[i+1][next[j][k]][1]%=mod;
}
}
for(int j=0;j<L;j++)
{
if(end[j])
{
f[i+1][j][1]+=f[i+1][j][0];
f[i+1][j][1]%=mod;
f[i+1][j][0]=0;
}
}
}
int ans=0;
for(int i=0;i<L;i++)
{
ans+=f[m][i][1];
ans%=mod;
}
return ans;
}
} tr;
int main()
{
tr.init();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
tr.insert(s);
}
tr.build();
printf("%d",tr.query(m));
return 0;
}