poj 2778 DNA Sequence
2016-07-24 20:20
363 查看
题目传送门
题意:
给出m个DNA序列,求出长度为n的不含上述序列的个数。(0 <= m <= 10),(1 <= n <=2000000000)题解:
首先我们应将DNA序列存入Tire中,之后可以构造一个矩阵A,A[i][j]表示从i节点状态是否可以一步转移到j节点状态。构造方法则很明显:沿着fail指针进行构造,如果它是被标记的序列那么就置为0。所以在BuildFail是要将没有儿子节点通过fail指针指向前面的节点。之后求出A^n求出方案数,ans=sigma(A[0][i])。#include <queue> #include <cstdio> #include <cstring> #include <iostream> using namespace std; inline char idx(const char &c) { switch (c) { case 'A' : return 0; case 'T' : return 1; case 'C' : return 2; case 'G' : return 3; } } //AC-auto const int MS = 110, Siz = 4; int ch[MS][Siz], root, totN, Fail[MS]; bool Unable[MS]; int NewNode() { Unable[++totN] = 0; memset(ch[totN], 0, sizeof ch[totN]); return totN; } void Insert(char *S) { int cur = root; char id; while (*S) { id = idx(*S); if (ch[cur][id]) { cur = ch[cur][id]; } else { cur = ch[cur][id] = NewNode(); } ++S; } Unable[cur] = 1; } void BuildFail() { queue<int>q; Fail[root] = root; for (int i = 0; i < Siz; ++i) if (ch[root][i]) { Fail[ch[root][i]] = root; q.push(ch[root][i]); } int f, p; while (!q.empty()) { p = q.front(); q.pop(); if (Unable[Fail[p]]) Unable[p] = 1; for (int i = 0; i < Siz; ++i) if (ch[p][i]) { f = Fail[p]; while (!ch[f][i] && f) f = Fail[f]; if (ch[f][i]) Fail[ch[p][i]] = ch[f][i]; else Fail[ch[p][i]] = root; q.push(ch[p][i]); } else { ch[p][i] = ch[Fail[p]][i];//构建假儿子 } } } //Matrix typedef long long LL; const int Mod = 100000; LL tmp1[MS][MS], tmp2[MS][MS]; void Matmul(LL A[MS][MS], LL B[MS][MS]){ memset(tmp1, 0, sizeof tmp1); for (int i = 0; i <= totN; ++i) for (int j = 0; j <= totN; ++j) for (int k = 0; k <= totN; ++k) tmp1[i][j] = (tmp1[i][j] + A[i][k] * B[k][j]) % Mod;; memcpy(A, tmp1, sizeof tmp1); } void MatPow(LL A[MS][MS], int n) { for (int i = totN; ~i; --i) for (int j = totN; ~j; --j) tmp2[i][j] = (i == j); while (n) { if (n & 1) Matmul(tmp2, A); Matmul(A, A); n >>= 1; } memcpy(A, tmp2, sizeof tmp2); } // void BuildMat(LL A[MS][MS]) { for (int i = 0; i <= totN; ++i) for (int j = 0; j < Siz; ++j) if (!Unable[i] && !Unable[ch[i][j]])//不是被标记的点才可以连接 ++A[i][ch[i][j]]; } char tmpS[12]; int main() { int n, m, tot; LL ans[MS][MS]; while (scanf("%d%d\n", &m, &n) == 2) { totN = -1; root = NewNode(); while (m--) { gets(tmpS); Insert(tmpS); } BuildFail(); memset(ans, 0, sizeof ans); BuildMat(ans); for (int i = 0; i <= totN; ++i) { for (int j = 0; j <= totN; ++j) printf("%d ", ans[i][j]); puts(""); } tot = 0; MatPow(ans, n); for (int i = 0; i <= totN; ++i) { tot += ans[0][i]; tot %= Mod; } printf("%d\n", tot); } return 0; }
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- [数论]poj2635__The Embarrassed Cryptographer
- [二分图匹配]poj2446__Chessboard
- POJ1050 最大子矩阵和
- 用单调栈解决最大连续矩形面积问题