题意
给出 m 个遗传病DNA片段(长度不大于10),再给一个整数 n 。问长度不超过 n 的DNA中有多少个不含有遗传病。
思路
链接
https://vjudge.net/contest/177933#problem/B
代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 120;
const int kind = 4;
int trie[maxn][kind], tt;
bool du[maxn];
int fail[maxn];
int id[100];
int m, n;
char str[15];
const int mod = 100000;
typedef long long LL;
LL mat0[maxn][maxn], mat1[maxn][maxn], mat2[maxn][maxn];
LL (*m0)[maxn], (*m1)[maxn], (*m2)[maxn];
void ins(char s[], int root)
{
int i = 0, p = root;
while(str[i] != '\0')
{
if(trie[p][id[str[i]]] == -1) trie[p][id[str[i]]] = ++tt;
p = trie[p][id[str[i]]];
i++;
}
du[p] = true;
}
void build_ac_automation(int root)
{
queue<int> qu;
fail[0] = 0;
for(int i = 0; i < kind; i++)
{
if(trie[0][i] != -1)
{
fail[trie[0][i]] = 0;
qu.push(trie[0][i]);
}
else trie[0][i] = 0;
}
while(qu.size())
{
int v = qu.front();
qu.pop();
if(du[fail[v]]) du[v] = true;
for(int i = 0; i < kind; i++)
{
int &u = trie[v][i];
if(u != -1)
{
fail[u] = trie[fail[v]][i];
qu.push(u);
}
else u = trie[fail[v]][i];
}
}
}
void mul(LL (*a)[maxn], LL (*b)[maxn])
{
memset(m1, 0, sizeof mat0);
for(int i = 0; i < tt; i++)
for(int k = 0; k < tt; k++)
for(int j = 0; j < tt; j++)
m1[i][j] = (m1[i][j] + a[i][k] * b[k][j]) % mod;
}
void power(int n)
{
memset(m2, 0, sizeof mat0);
for(int i = 0; i < tt; i++)
m2[i][i] = 1;
while(n > 0)
{
if(n & 1) mul(m2, m0), swap(m2, m1);
mul(m0, m0), swap(m0, m1);
n >>= 1;
}
}
int main()
{
// freopen("in.txt", "r", stdin);
id['A'] = 0, id['T'] = 1, id['C'] = 2, id['G'] = 3;
memset(trie, -1, sizeof trie);
memset(fail, -1, sizeof fail);
scanf("%d %d", &m, &n);
for(int i = 0; i < m; i++)
{
scanf(" %s", str);
ins(str, 0);
}
tt ++;
build_ac_automation(0);
for(int i = 0; i < tt; i++)
for(int j = 0; j < kind; j++)
if(!du[i] && !du[trie[i][j]]){
mat0[i][trie[i][j]] ++;
}
m0 = mat0;
m1 = mat1;
m2 = mat2;
power(n);
int res = 0;
for(int i = 0; i < tt; i++)
res += m2[0][i];
res %= mod;
cout << res << endl;
return 0;
}