Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 13502 | Accepted: 5143 |
Description
Input
Output
Sample Input
4 3 AT AC AG AA
Sample Output
36
题意:给你n个DNA模式串,若DNA序列中含有模式串,则说明患病。现在问你m长度的DNA序列中有多少种不患病的。
建议看下这道题——离散数学的应用:点我
注意:要理解AC自动机里面状态转移的前提。若fail[now]指针没有指向root,说明fail[now]指向节点序列的前缀是当前节点序列的某个后缀。
思路:构建出AC自动机的trie,标记所有模式串的序列结点。在BFS建状态图时,若trie上某个节点u通过失配指针可以到达某个模式串,则说明此处不通,标记。 最后构建矩阵,行列均为trie节点数,求出矩阵的m次幂,累加0节点即根到trie上所有节点的矩阵值就是答案。
因为0节点是trie的根,在矩阵所表示的图中是不存在的,所以求出矩阵的m次幂才是m长度串的所有数目,而不是m-1次幂。
测试数据没过,原来这里求的是矩阵的m-1次幂 o(╯□╰)o
AC代码:
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #define MAXN 120 #define LL long long #define MOD 100000 using namespace std; struct Matrix{ LL a[MAXN][MAXN]; int N; }; Matrix ori, res; void init_a(int NN) { memset(ori.a, 0, sizeof(ori.a)); memset(res.a, 0, sizeof(res.a)); ori.N = res.N = NN; for(int i = 0; i < NN; i++) res.a[i][i] = 1; } struct Trie { int next[MAXN][4], fail[MAXN], End[MAXN]; int L, root; int newnode() { for(int i = 0; i < 4; i++) next[L][i] = -1; End[L++] = 0; return L-1; } void init() { L = 0; root = newnode(); } int getval(char op) { if(op == 'A') return 0; if(op == 'C') return 1; if(op == 'G') return 2; if(op == 'T') return 3; } void Insert(char *s) { int len = strlen(s); int now = root; for(int i = 0; i < len; i++) { int v = getval(s[i]); if(next[now][v] == -1) next[now][v] = newnode(); now = next[now][v]; } End[now] = 1; } void Build() { queue<int> Q; fail[root] = root; for(int i = 0; i < 4; i++) { if(next[root][i] == -1) next[root][i] = root; else { fail[next[root][i]] = root; Q.push(next[root][i]); } } while(!Q.empty()) { int now = Q.front(); Q.pop(); if(End[fail[now]] == 1)//失配边所指 为模式串 End[now] = 1;//此处不通 for(int i = 0; i < 4; i++) { if(next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; Q.push(next[now][i]); } } } } void getMatrix() { for(int i = 0; i < L; i++) if(End[i] == 0) for(int j = 0; j < 4; j++) if(End[next[i][j]] == 0)//所有通路 ori.a[i][next[i][j]]++; } }; Trie ac; Matrix multi(Matrix x, Matrix y) { Matrix z; memset(z.a, 0, sizeof(z.a)); z.N = x.N; for(int i = 0; i < x.N; i++) { for(int k = 0; k < y.N; k++) { if(x.a[i][k] == 0) continue; for(int j = 0; j < x.N; j++) z.a[i][j] = (z.a[i][j] + (x.a[i][k] * y.a[k][j]) % MOD) % MOD; } } return z; } void solve(int n) { while(n) { if(n & 1) res = multi(ori, res); ori = multi(ori, ori); n >>= 1; } LL ans = 0; for(int i = 0; i < res.N; i++) ans = (ans + res.a[0][i]) % MOD; printf("%lld\n", ans); } char str[120]; int main() { int n, m; while(scanf("%d%d", &n, &m) != EOF) { ac.init(); for(int i = 0; i < n; i++) scanf("%s", str), ac.Insert(str); ac.Build(); init_a(ac.L); ac.getMatrix(); solve(m); } return 0; }