DNA Sequence - POJ 2778
- 题意:给出m个有毒的DNA序列,问长度为n的DNA序列中正常的序列(不包含有毒的序列)有多少个。
思路:
- 定义mat[ i ][ j ]表示从结点 i 一步走到结点 j 共有多少种方法。
- 那么从结点 i 走n个合法步到达结点 j 就共有种方法。n很大,用到了矩阵快速幂。
- 那么最后的答案就是 sum() (0 <= i <= tot(结点总数))。为什么不是矩阵元素全都加起来,是因为重复啦。
关于TLE:
- 矩阵相乘的时候,要对应行列乘完之后再取模,不然每次取mod就炸掉了。好坑……
AC CODE
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long ll;
const int mod = 100000;
int N;
int getNum(char ch)
{
switch(ch)
{
case 'A': return 0;
case 'C': return 1;
case 'T': return 2;
case 'G': return 3;
}
}
struct MAT{
ll mat[105][105];
void init() { memset(mat, 0, sizeof(mat)); }
void getE()
{
init();
for(int i = 0; i <= N; ++ i )
mat[i][i] = 1;
}
friend MAT operator * (MAT a, MAT b)
{
MAT ans; ans.init();
for(int i = 0; i <= N; ++ i )//新矩阵的行,矩阵a的行
for(int j = 0; j <= N; ++ j )//新矩阵的列,矩阵b的列
{
for(int k = 0; k <= N; ++ k )//矩阵a的列,矩阵b的行
ans.mat[i][j] += a.mat[i][k] * b.mat[k][j];
ans.mat[i][j] %= mod;
}
return ans;
}
};
class AC_aotomat{
public:
int trie[105][4], tot;
int fail[105];
bool tag[105];
public:
void Clear(int rt)
{
for(int i = 0; i < 4; ++ i ) trie[rt][i] = 0;
}
void init()
{
Clear(0);
tot = 0;
memset(tag, false, sizeof(tag));
}
void Insert(char *s)
{
int rt = 0;
for(int i = 0; s[i] ; ++ i )
{
int id = getNum(s[i]);
if(!trie[rt][id]) { trie[rt][id] = ++ tot; Clear(tot); }
rt = trie[rt][id];
}
tag[rt] = true;
}
void build()
{
queue<int>q;
for(int i = 0; i < 4; ++ i )
if(trie[0][i])
{ q.push(trie[0][i]); fail[trie[0][i]] = 0; }
while(!q.empty())
{
int rt = q.front(); q.pop();
if(fail[rt] && tag[fail[rt]]) tag[rt] = true;
for(int i = 0; i < 4; ++ i )
{
if(trie[rt][i])
{
fail[trie[rt][i]] = trie[fail[rt]][i];
q.push(trie[rt][i]);
} else trie[rt][i] = trie[fail[rt]][i];
}
}
}
MAT getMatrix()
{
N = tot;
MAT mt; mt.init();
for(int i = 0; i <= tot; ++ i )
for(int j = 0; j < 4; ++ j )
if(!tag[i] && !tag[trie[i][j]])
++ mt.mat[i][trie[i][j]];
return mt;
}
void print(MAT mt)
{
ll ans = 0;
for(int i = 0; i <= tot; ++ i )
ans += mt.mat[0][i], ans %= mod;
printf("%lld\n", ans % mod);
}
}ac;
MAT FastPowOfMat(MAT x, ll y)
{
MAT ans, base = x;
ans.getE();
while(y)
{
if(y & 1)
ans = ans * base;
base = base * base;
y >>= 1;
}
return ans;
}
int m; ll n;
int main()
{
scanf("%d%lld", &m, &n);
ac.init();
for(int i = 1; i <= m; ++i )
{
char str[15]; scanf("%s", str);
ac.Insert(str);
}
ac.build();
MAT ansMat = FastPowOfMat(ac.getMatrix(), n);
ac.print(ansMat);
return 0;
}