DNA Sequence POJ - 2778 ac自动机+矩阵快速幂

一、内容

It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's very useful to analyze a segment of DNA Sequence,For example, if a animal's DNA sequence contains segment ATC then it may mean that the animal may have a genetic disease. Until now scientists have found several those segments, the problem is how many kinds of DNA sequences of a species don't contain those segments.

Suppose that DNA sequences of a species is a sequence that consist of A, C, T and G,and the length of sequences is a given integer n.

Input

First line contains two integer m (0 <= m <= 10), n (1 <= n <=2000000000). Here, m is the number of genetic disease segment, and n is the length of sequences.

Next m lines each line contain a DNA genetic disease segment, and length of these segments is not larger than 10.

Output

An integer, the number of DNA sequences, mod 100000. 

Sample Input

4 3
AT
AC
AG
AA

Sample Output

36

二、思路

在这里插入图片描述在这里插入图片描述

三、代码

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int N = 205, MOD = 1e5;
int n, m, len, tr[N][4], ne[N], fail[N];
char s[N]; 
struct Martrix {
	long long a[N][N];
	Martrix() { 
		for (int i = 0; i <= len; i++) {
			for (int j = 0; j <= len; j++) a[i][j] = 0;
		}
	}//初始化
};
int getId(char c) {
	if (c == 'A') return 0;
	if (c == 'T') return 1;
	if (c == 'G') return 2; return 3;
} 
void add() {
	int p = 0;
	for (int i = 0; s[i]; i++) {
		int j = getId(s[i]);
		if (!tr[p][j]) tr[p][j] = ++len;
		p = tr[p][j];
	}
	fail[p] = 1; //危险节点 
}
void build() {
	queue<int> q;
	for (int i = 0; i < 4; i++) {
		if (tr[0][i]) q.push(tr[0][i]);
	}
	while (!q.empty()) {
		int p = q.front(); q.pop();
		for (int j = 0; j < 4; j++) {
			int c = tr[p][j];
			if (!c) tr[p][j] = tr[ne[p]][j];
			else {
				ne[c] = tr[ne[p]][j];
				fail[c] |= fail[ne[c]]; //若后缀是病毒也要算上 
				q.push(c);
			}
		}
	} 
}
Martrix mul(Martrix &A, Martrix &B) {
	Martrix C;
	for (int i = 0; i <= len; i++) {
		for (int j = 0; j <= len; j++) {
			C.a[i][j] = 0;
			for (int k = 0; k <= len; k++) {
				C.a[i][j] += (A.a[i][k] * B.a[k][j]);
			}
			C.a[i][j] %= MOD; //MOD不大取余一次即可 
		}
	}
	return C;
} 
void solve() {
	//通过trie数 构建A
	Martrix A, ans; 
	for (int p = 0; p <= len; p++) {
		for (int j = 0; j < 4; j++) {
			int c = tr[p][j];
			if (!fail[c] && !fail[p]) A.a[p][c]++; //代表有边可走 
		}
	}
	//通过A 求出A^M
	for (int i = 0; i <= len; i++) ans.a[i][i] = 1;
	while (m) {
		if (m & 1) {
			ans = mul(ans, A);
		}
		A = mul(A, A);
		m >>= 1;
	} 
	
	long long sum = 0;
	for (int i = 0; i <= len; i++) sum = (sum + ans.a[0][i]) % MOD;
	printf("%lld", sum);
}
int main() {
	scanf("%d%d", &n, &m);	
	for (int i = 1; i <= n; i++) {
		scanf("%s", s); add();
	}
	build(); 
	solve();
	return 0;
} 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值