DNA Sequence
基因序列可以看做是只含大写ACGT 的字符串。
现有n 个癌症序列,每个癌症序列有至多10 个字符。
现请问不含癌症序列的长度为len 的基因有多少个?答案对100000 取模。
【输入格式】
第一行两个数n, len,表示癌症序列的个数和待求基因的长度。
接下来n 行,每一行一个字符串,表示癌症序列。
【输出格式】
一个整数,表示不含癌症序列的长度为len 的基因有多少个?答案对
100000 取模。
【输入样例】
4 3
AT
AC
AG
AA
【输出样例】
36
【数据规模】
10% 数据满足len ≤ 10。
90% 数据满足len ≤ 1000
100% 数据满足0 ≤ n ≤ 10, 1 ≤ len ≤ 2000000000
将题目简化,只有4个字母,给出模板串,求规定长度内的单词有多少不含模板串
建立trie的邻接矩阵M
M[i][j]表示i到j只走一步的走法
M的n次幂就是i到j走n步有多少种走法
删除癌症序列结点所在的行和列
将单词结尾(即癌症序列结尾)与fail直接指向癌症序列的节点删除
计算M的n次幂,ans=Σ(M[0,i])%100000
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <iomanip>
#include <ctime>
#include <climits>
#include <cctype>
#include <algorithm>
#define clr(x) memset(x,0,sizeof(x))
#define LL long long
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int MOD = 100000;
const int maxn = 105;
const int kind = 4;
typedef LL M[maxn][maxn];
M mat,mat1,mat2;
LL (*m1)[maxn],(*m2)[maxn];
class AC_DFA {
public:
int n,id['Z'+1],fail[maxn],trie[maxn][kind];
bool tip[maxn];
void makeID() { id['A'] = 0; id['T'] = 1; id['C'] = 2; id['G'] = 3; }
void reset() {
memset(trie[0], -1, sizeof(trie[0]));
tip[0] = false; n = 1;
}
void add(char *s) {
int p = 0;
while(*s) {
int i = id[*s];
if(trie[p][i] == -1) {
memset(trie[n], -1, sizeof(trie[n]));
tip[n] = false;
trie[p][i] = n++;
}
p = trie[p][i];
s++;
}
tip[p] = true;
}
void setfail() {
queue<int> Q;
fail[0] = 0;
for(int i = 0; i < kind; i++)
if(-1 != trie[0][i]) fail[trie[0][i]] = 0, Q.push(trie[0][i]);
else trie[0][i] = 0;
while(!Q.empty()) {
int u = Q.front();
Q.pop();
if(tip[fail[u]]) tip[u] = true;
for(int i = 0; i < kind; i++) {
int &v = trie[u][i];
if(v != -1) Q.push(v), fail[v] = trie[fail[u]][i];
else v = trie[fail[u]][i];
}
}
}
void build() {
clr(mat);
for(int i = 0; i < n; i++)
for(int j = 0; j < kind; j++)
if(!tip[i] && !tip[trie[i][j]]) mat[i][trie[i][j]]++;
}
}AC;
void mult(M t1, M t2, M r)
{
for(int i = 0; i < AC.n; i++)
for(int j = 0; j < AC.n; j++)
{
r[i][j] = 0;
for(int k = 0; k < AC.n; k++) r[i][j] += t1[i][k] * t2[k][j];
r[i][j] %= 100000;
}
}
void power(int p) { //快速幂
if(p == 1) {
for(int i = 0; i < AC.n; i++)
for(int j = 0; j < AC.n; j++) m2[i][j] = mat[i][j];
return;
}
power(p>>1);
mult(m2, m2, m1);
if(p%2) mult(m1, mat, m2);
else swap(m1, m2);
}
int main() {
freopen("gene.in","r",stdin);
freopen("gene.out","w",stdout);
int n,m;
char s[12];
AC.makeID();
scanf("%d%d",&m,&n);
AC.reset();
while(m--) scanf("%s",s), AC.add(s);
AC.setfail(); AC.build();
m1 = mat1; m2 = mat2;
power(n);
int ans = 0;
for(int i = 0; i < AC.n; i++) ans += m2[0][i];
printf("%d\n",ans%MOD);
return 0;
}