POJ-2778 DNA Sequence(AC自动机+矩阵快速幂)

96 篇文章 0 订阅
6 篇文章 0 订阅

Description

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

Source



题意:给你一堆DNA子串,让你求长度为n且不包含这些子串的DNA序列有多少个。


分析:AC自动机构造的同时构造转移矩阵,然后上矩阵快速幂。


#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define MAXNODE 105
using namespace std;
int m,n;
char s[15];
struct Acautomata
{
	int ch[MAXNODE][4];
	int f[MAXNODE];
	long long matrix[MAXNODE][MAXNODE];
	bool jud[MAXNODE];
	int tot;
	void init()
	{
		tot = 1;
		memset(ch[0],0,sizeof(ch[0]));
		memset(matrix,0,sizeof(matrix));
	}
	int idx(char c)
	{
		if(c == 'A') return 0;
		if(c == 'T') return 1;
		if(c == 'C') return 2;
		if(c == 'G') return 3;
	}
	void insert(char *s)
	{
		int u = 0,n = strlen(s);
		for(int i = 0;i < n;i++)
		{
			int c = idx(s[i]);
			if(!ch[u][c])
			{
				memset(ch[tot],0,sizeof(ch[tot]));
				jud[tot] = false;
				ch[u][c] = tot++;
			}
			u = ch[u][c];
		}
		jud[u] = true;
	}
	void getFail()
	{
		queue<int> q;
		f[0] = 0;
		for(int c = 0;c < 4;c++)
		{
			int u = ch[0][c];
			if(u)
			{
				f[u] = 0;
				q.push(u);
				if(!jud[u]) matrix[0][u]++;
			}
			else matrix[0][0]++;
		}
		while(!q.empty())
		{
			int r = q.front();q.pop();
			for(int c = 0;c < 4;c++)
			{
				int u = ch[r][c];
				if(!u)
				{
					ch[r][c] = ch[f[r]][c];
					if(!jud[ch[r][c]]) matrix[r][ch[r][c]]++;
					continue;
				}
				q.push(u);
				f[u] = ch[f[r]][c];
				jud[u] = jud[u] || jud[f[u]];
				if(!jud[u]) matrix[r][u]++;
			}
		}
	}
	void matrixmul(const long long a[105][105],const long long b[105][105],long long c[105][105])
	{
		long long t[105][105];
		memset(t,0,sizeof(t));
		for(int i = 0;i < tot;i++)
		 for(int j = 0;j < tot;j++) 
		  for(int k = 0;k < tot;k++) 
		   t[i][j] = t[i][j] + a[i][k]*b[k][j] % 100000;
		for(int i = 0;i < tot;i++)
		 for(int j = 0;j < tot;j++)
		  c[i][j] = t[i][j];
	}
	int deal(int n)
	{
		long long ans[105][105];
		memset(ans,0,sizeof(ans));
		for(int i = 0;i < tot;i++) ans[i][i] = 1ll;
		while(n)
		{
			if(n & 1) matrixmul(ans,matrix,ans);
			matrixmul(matrix,matrix,matrix);
			n>>=1;
		}
		int num = 0;
		for(int i = 0;i < tot;i++) num = (num + ans[0][i]) % 100000;
		return num; 
	}
} tree;
int main()
{
	cin.sync_with_stdio(false);
	cin>>m>>n;
	tree.init();
	for(int i = 1;i <= m;i++)
	{
		cin>>s;
		tree.insert(s); 
	}
	tree.getFail();
	cout<<tree.deal(n)<<endl;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值