POJ 2778 DNA Sequence ( Trie图、矩阵快速幂 )
题意 : 给出一些病毒串,问你由ATGC构成的长度为 n 且不包含这些病毒串的个数有多少个
分析:
我们先分析Tire 图的结构 : Trie图是在AC自动机的原型上增添边使得状态可以快速转移,标记危险的节点(后缀是不良单词的节点); 那我们是想构造长度是n不包含不良串对不对 , 那是不是在trie图上从0节点走n步到安全节点的方案数(Trie图也是状态转移图)
在一个有向图中,A走k步到B的方案数(这显然是经典的矩阵快速幂问题),(原理需要自己搜索)先对原图建立一个邻接表M[i][j] , M[i][j] =1表示i到j有边直接相连,然后ans=pow(M,k) ,ans[A][B] 为答案
#include<queue> #include<stdio.h> #include<string.h> using namespace std; const int Max_Tot = 1e2 + 10; const int Letter = 4; const int MOD = 1e5; int maxn; int mp[128]; struct mat{ int m[111][111]; }unit, M; mat operator * (mat a, mat b) { mat ret; long long x; for(int i=0; i<maxn; i++){ for(int j=0; j<maxn; j++){ x = 0; for(int k=0; k<maxn; k++){ x += (long long)a.m[i][k]*b.m[k][j]; } ret.m[i][j] = x % MOD; } } return ret; } inline void init_unit() { for(int i=0; i<maxn; i++) unit.m[i][i] = 1; } mat pow_mat(mat a, int n) { mat ret = unit; while(n){ if(n&1) ret = ret * a; a = a*a; n >>= 1; } return ret; } struct Aho{ struct StateTable{ int Next[Letter]; int fail, flag; }Node[Max_Tot]; int Size; queue<int> que; inline void init(){ while(!que.empty()) que.pop(); memset(Node[0].Next, 0, sizeof(Node[0].Next)); Node[0].fail = Node[0].flag = 0; Size = 1; } inline void insert(char *s){ int now = 0; for(int i=0; s[i]; i++){ int idx = mp[s[i]]; if(!Node[now].Next[idx]){ memset(Node[Size].Next, 0, sizeof(Node[Size].Next)); Node[Size].fail = Node[Size].flag = 0; Node[now].Next[idx] = Size++; } now = Node[now].Next[idx]; } Node[now].flag = 1; } //1) 如果son[i]不存在,将它指向 当前结点now的fail指针指 //向结点的i号后继(保证一定已经计算出来)。 //2) 如果son[i]存在,将它的fail指针指向 当前结点now的fail //指针指向结点的i号后继(保证一定已经计算出来)。 inline void BuildFail(){ Node[0].fail = 0; for(int i=0; i<Letter; i++){ if(Node[0].Next[i]){ Node[Node[0].Next[i]].fail = 0; que.push(Node[0].Next[i]); }else Node[0].Next[i] = 0;///必定指向根节点 } while(!que.empty()){ int top = que.front(); que.pop(); if(Node[Node[top].fail].flag) Node[top].flag = 1; for(int i=0; i<Letter; i++){ int &v = Node[top].Next[i]; if(v){ que.push(v); Node[v].fail = Node[Node[top].fail].Next[i]; }else v = Node[Node[top].fail].Next[i]; } } } inline void BuildMatrix(){ for(int i=0; i<Size; i++) for(int j=0; j<Size; j++) M.m[i][j] = 0; for(int i=0; i<Size; i++){ for(int j=0; j<Letter; j++){ if(!Node[i].flag && !Node[ Node[i].Next[j] ].flag) M.m[i][Node[i].Next[j]]++; } } maxn = Size; } }ac; char S[11]; int main(void) { mp['A']=0, mp['T']=1, mp['G']=2, mp['C']=3; int n, m; while(~scanf("%d %d", &m, &n)){ ac.init(); for(int i=0; i<m; i++){ scanf("%s", S); ac.insert(S); } ac.BuildFail(); ac.BuildMatrix(); // for(int i=0; i<10; i++){ // for(int j=0; j<10; j++){ // printf("%d ", M.m[i][j]); // }puts(""); // }puts(""); init_unit(); M = pow_mat(M, n); // for(int i=0; i<10; i++){ // for(int j=0; j<10; j++){ // printf("%d ", M.m[i][j]); // }puts(""); // }puts(""); int ans = 0; for(int i=0; i<ac.Size; i++) ans += M.m[0][i]; ans %= MOD; printf("%d\n", ans); } return 0; }