题目大意:DNA序列是有 ATGC 组成的,现在知道一些动物的遗传片段有害的,那么如果给出这些有害的片段,能否求出来所有长度为 N 的基因中有多少是不包含这些有害片段的。
分析:也是断断续续做了一天,做这道题前先做一下 hdu2157 这道题,因为这道题的思路就是从它转变过来的,看明白了这个后,就需要构造一个矩阵,不过因为按照自己的想法构造的矩阵,一直WA,不明白为什么,后来发现是因为在子节点不存在时候查询后缀时候包含子节点的时候不彻底造成的,还是对AC自动机了解的不多。不过通过这题也学会了矩阵快速幂,算是不错的收获。
代码如下:
==========================================================================================================================
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std; const int MAXN = 107; const int MAXM = 4; const int mod = 100000; struct Matrix{long long edge[MAXN][MAXN];}; struct TrieNode { TrieNode *Fail, *next[MAXM]; int danger, Num;///节点编号,是否是危险指针 }; int GetVal(char ch) { if(ch == 'A')return 0; if(ch == 'T')return 1; if(ch == 'G')return 2; return 3; } void Insert(TrieNode *root, char s[], int &Num) { TrieNode *p = root; for(int i=0; s[i]; i++) { int k = GetVal(s[i]); if(p->next[k] == NULL) { p->next[k] = new TrieNode(); p->next[k]->Num = ++Num; } p = p->next[k]; } p->danger = true; } void GetFail(TrieNode *root) { TrieNode *p = root, *temp; queue<TrieNode *> Q; for(int i=0; i<MAXM; i++) { if(p->next[i]) { p->next[i]->Fail = root; Q.push(p->next[i]); } } while(Q.size()) { p = Q.front(); Q.pop(); for(int i=0; i<MAXM; i++)if(p->next[i]) { temp = p->Fail; while(temp != NULL) { if(temp->next[i] != NULL) { p->next[i]->Fail = temp->next[i]; ///如果这个后缀是危险节点的话,那么向下传递一下 p->next[i]->danger |= temp->next[i]->danger; break; } temp = temp->Fail; } if(temp == NULL) p->next[i]->Fail = root; Q.push(p->next[i]); } } root->Fail = root; } void GetMatrix(TrieNode *root, Matrix &Map) { TrieNode *p = root, *temp; if(p->danger)return ; for(int i=0; i<MAXM; i++) { if(p->next[i]) GetMatrix(p->next[i], Map); temp = p; ///当p->next[i] 不存在时,访问它的后缀Fail,直到根节点停止 while(temp->Num != 0 && !temp->next[i]) temp = temp->Fail; if(!temp->next[i]) {///如果在前后缀没有找到,那么就走向根节点处 Map.edge[p->Num][0]++; continue; } ///如果这个点是危险节点 if(temp->next[i]->danger)continue; Map.edge[p->Num][temp->next[i]->Num]++; } } void Mul(Matrix a, Matrix b, Matrix &ans, int len) { memset(ans.edge, 0, sizeof(ans.edge)); for(int i=0; i<=len; i++) for(int j=0; j<=len; j++) for(int k=0; k<=len; k++) { ans.edge[i][j] += a.edge[i][k] * b.edge[k][j]; ans.edge[i][j] %= mod; } } void QuickPow(Matrix Map, long long k, Matrix &ans, int len) { memset(ans.edge, 0, sizeof(ans.edge)); for(int i=0; i<=len; i++) ans.edge[i][i] = 1; while(k) { if(k & 1) Mul(ans, Map, ans, len); Mul(Map, Map, Map, len); k /= 2; } } void FreeTrie(TrieNode *root) { for(int i=0; i<MAXM; i++) { if(root->next[i]) FreeTrie(root->next[i]); } free(root); } int main() { long long M, K; while(scanf("%lld%lld", &M, &K) != EOF) { char s[MAXN]; int num = 0; TrieNode *root = new TrieNode(); while(M--) { scanf("%s", s); Insert(root, s, num); } GetFail(root); Matrix Map, ans; memset(Map.edge, 0, sizeof(Map.edge)); GetMatrix(root, Map); QuickPow(Map, K, ans, num); long long sum=0; for(int i=0; i<=num; i++) { sum = (sum + ans.edge[0][i]) % mod; } printf("%lld ", sum); FreeTrie(root); } return 0; }