poj 2778

http://poj.org/problem?id=2778
题目大意是,检测所有可能的n位DNA串有多少个DNA串中不含有指定的病毒片段。合法的DNA只能由ACTG四个字符构成。题目将给出10个以内的病毒片段,每个片段长度不超过10。数据规模n<=2 000 000 000。

这道题真的让我很痛苦,debug3天未果。
AC自动机加矩阵乘法。
核心思想是,一个长度为n的字符串的匹配相当于在一个构造好的字典树上从root开始走n步。所以所有的走法也都是在这个字典树上进行的。关键就在于不能走到ed[i]的节点的判断,与ed[i]等价的节点也属于不能走到的节点,所以如果当前节点的fail节点ed为1时,当前节点ed也为1.

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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<string.h>
#include<iostream>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
#define mem(x,y) memset(x,y,sizeof(x))
#define inf 0x3f3f3f3f
#define debug puts("-----")
#define maxn 100+5
int siz;
int mod=100000;
struct matrix
{
long long a[maxn][maxn];
matrix operator*(const matrix &t)const
{
matrix res;
mem(res.a,0);
for(int i=0;i<siz;i++)
for(int j=0;j<siz;j++)
if(a[i][j])
for(int k=0;k<siz;k++)
res.a[i][k]=(res.a[i][k]+a[i][j]*t.a[j][k])%mod;
return res;
}
matrix operator*=(const matrix &t)
{
*this=t* *this;
return *this;
}
}a;
struct trie
{
int next[maxn][4],fail[maxn],ed[maxn];
map<char,int>mp;
int root,L;
int newnode()
{

mem(next[L],-1);
ed[L]=0;
return L++;
}
void init()
{

L=0;
root=newnode();
mem(a.a,0);
mp['A']=0,mp['C']=1,mp['G']=2,mp['T']=3;
}
void insert(char s[])
{

int len=strlen(s);
int now=root;
for(int i=0;i<len;i++)
{
int &t=next[now][mp[s[i]]];
if(t==-1)
{
t=newnode();
}
now=t;
}
ed[now]=1;
}
void build()
{

queue<int>q;
for(int i=0;i<4;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();
if(ed[fail[now]])
ed[now]=1;
for(int i=0;i<4;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]);
}
}
for(int i=0;i<L;i++)
{
for(int j=0;j<4;j++)
if(ed[next[i][j]]==0)
a.a[i][next[i][j]]++;
}
siz=L;
}
};
trie ac;
matrix qmod(int k)
{

matrix res;
mem(res.a,0);
for(int i=0;i<siz;i++)
res.a[i][i]=1;
while(k)
{
if(k&1)
res*=a;
a*=a;
k>>=1;
}
return res;
}
void print(matrix t)
{

for(int i=0;i<siz;i++)
{
for(int j=0;j<siz;j++)
printf("%d ",t.a[i][j]);
puts("");
}
}
char s[20];
int main()
{

int m,n;
scanf("%d%d",&m,&n);
matrix t;
ac.init();
while(m--)
{
scanf("%s",s);
ac.insert(s);
}
ac.build();
t=qmod(n);

long long ans=0;
for(int i=0;i<siz;i++)
{
ans+=t.a[0][i];
}
printf("%d\n",ans%mod);
}

EOF