链接:
https://vjudge.net/problem/POJ-2778
题意:
It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to analyze a segment of DNA Sequence,For example, if a animal's DNA sequence contains segment ATC then it may mean that the animal may have a genetic disease. Until now scientists have found several those segments, the problem is how many kinds of DNA sequences of a species don't contain those segments.
Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n.
思路:
我们把病毒序列做成一个Trie图, 我们就是在这个有向图上走n步能构成多少个字符串.
考虑某些结尾的点不能走, 因为走到了就形成了病毒序列, 同时某个节点的Fail指针指向的节点是病毒结尾节点这个点同样不能走.以为走到了, 形成的后缀中就存在病毒序列.
吧所有能走的点列成一个矩阵, 同时先求出走一步的矩阵, 考虑从a->b, 就是a->x, x->b,可以通过矩阵乘法求出所有a->b的方法.
考虑矩阵快速幂.
代码偷懒直接重载运算符写法.
再上一个大佬题解(特别清晰):https://blog.csdn.net/morgan_xww/article/details/7834801
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
//#include <memory.h>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <stack>
#include <string>
#include <assert.h>
#include <iomanip>
#include <iostream>
#include <sstream>
#define MINF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const int MOD = 1e5;
const int MAXN = 2e6+10;
struct AcTree
{
int Next[4];
int fail;
int end;
int ok;
void Init()
{
memset(Next, 0, sizeof(Next));
end = 0;
fail = 0;
ok = 1;
}
}tree[MAXN];
struct Martix
{
LL mar[110][110];
int n;
void Inin(const int *key, int len, const int *value)
{
memset(mar, 0, sizeof(mar));
n = len;
for (int i = 1;i <= n;i++)
{
for (int j = 0;j < 4;j++)
{
int node = tree[key[i]].Next[j];
if (tree[node].ok == 0)
continue;
mar[i][value[node]]++;
// cout << key[i] << ' ' << node << endl;
}
}
}
Martix& operator * (const Martix& that)
{
LL tmp[110][110];
for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= n;j++)
{
LL tmpval = 0;
for (int k = 1;k <= n;k++)
tmpval = (tmpval+(this->mar[i][k]*that.mar[k][j])%MOD)%MOD;
tmp[i][j] = tmpval;
}
}
for (int i = 1;i <= n;i++)
{
for (int j = 1;j <= n;j++)
this->mar[i][j] = tmp[i][j];
}
return *this;
}
}Mar;
map<char, int> Mp;
char s[MAXN];
int Key[110], Value[110*110];
LL n, m, cnt;
void Insert(char *s)
{
int len = strlen(s);
int pos = 0;
for (int i = 0;i < len;i++)
{
if (tree[pos].Next[Mp[s[i]]] == 0)
{
tree[pos].Next[Mp[s[i]]] = ++cnt;
tree[cnt].Init();
}
pos = tree[pos].Next[Mp[s[i]]];
}
tree[pos].end = 1;
tree[pos].ok = 0;
}
void BuildAC()
{
queue<int> que;
for (int i = 0;i < 4;i++)
{
if (tree[0].Next[i] != 0)
tree[tree[0].Next[i]].fail = 0, que.push(tree[0].Next[i]);
}
while (!que.empty())
{
int u = que.front();
que.pop();
if (tree[tree[u].fail].ok == 0)
tree[u].ok = 0;
for (int i = 0;i < 4;i++)
{
if (tree[u].Next[i] != 0)
{
tree[tree[u].Next[i]].fail = tree[tree[u].fail].Next[i];
que.push(tree[u].Next[i]);
}
else
tree[u].Next[i] = tree[tree[u].fail].Next[i];
}
}
}
Martix QuickMartixMi(Martix a, LL b)
{
b--;
Martix res = a;
while (b)
{
if (b&1)
res*a;
a*a;
b >>= 1;
}
return res;
}
int main()
{
Mp['A'] = 0;
Mp['T'] = 1;
Mp['G'] = 2;
Mp['C'] = 3;
while(~scanf("%d%d", &m, &n))
{
cnt = 0;
tree[0].Init();
for (int i = 1; i <= m; i++)
{
scanf("%s", s);
Insert(s);
}
BuildAC();
int tmp = 0;
for (int i = 0;i <= cnt;i++)
{
if (tree[i].ok)
Key[++tmp] = i, Value[i] = tmp;
}
Mar.Inin(Key, tmp, Value);
Martix res = QuickMartixMi(Mar, n);
LL ans = 0;
for (int i = 1;i <= res.n;i++)
ans = (ans+res.mar[1][i])%MOD;
printf("%lld
", ans);
}
return 0;
}