[POJ2778]DNA Sequence(AC自动机 + DP + 矩阵优化)

传送门

AC自动机加DP就不说了

注意到 m <= 10,所以模式串很少。

而 n 很大就需要 log 的算法,很容易想到矩阵。

但是该怎么构建?

还是矩阵 A(i,j) = ∑A(i,k) * A(k,j),那么i到j的方案数就是j到k的方案数称k到j的方案数,那么直接矩阵快速幂即可

#include <queue>
#include <cstdio>
#include <cstring>
#define N 100001
#define p 100000
#define LL long long

int n, m, cnt, ans;
int next[N][4], fail[N], f[101][N];
bool val[N];
char s[N];
std::queue <int> q;

struct Matrix
{
	int n, m;
	LL a[141][141];
	Matrix()
	{
		n = m = 0;
		memset(a, 0, sizeof(a));
	}
}res;

inline int idx(char x)
{
	if(x == ‘A‘) return 0;
	if(x == ‘C‘) return 1;
	if(x == ‘T‘) return 2;
	if(x == ‘G‘) return 3;
}

inline void insert()
{
	int i, x, now = 0, len = strlen(s + 1);
	for(i = 1; i <= len; i++)
	{
		x = idx(s[i]);
		if(!next[now][x])
			next[now][x] = ++cnt;
		now = next[now][x];
	}
	val[now] = 1;
}

inline void make_fail()
{
	int i, now;
	for(i = 0; i < 4; i++)
		if(next[0][i])
			q.push(next[0][i]);
	while(!q.empty())
	{
		now = q.front();
		q.pop();
		for(i = 0; i < 4; i++)
		{
			if(!next[now][i])
			{
				next[now][i] = next[fail[now]][i];
				continue;
			}
			fail[next[now][i]] = next[fail[now]][i];
			val[next[now][i]] |= val[next[fail[now]][i]];
			q.push(next[now][i]);
		}
	}
}

inline Matrix operator * (Matrix x, Matrix y)
{
	int i, j, k;
	Matrix ret;
	ret.n = x.n;
	ret.m = y.m;
	for(i = 0; i <= x.n; i++)
		for(j = 0; j <= y.m; j++)
			for(k = 0; k <= y.n; k++)
				ret.a[i][j] = (ret.a[i][j] + x.a[i][k] * y.a[k][j]) % p;
	return ret;
}

inline Matrix operator ^ (Matrix x, int y)
{
	int i;
	Matrix ret;
	res.n = ret.m = cnt;
	for(i = 0; i <= cnt; i++) ret.a[i][i] = 1;
	for(; y; y >>= 1)
	{
		if(y & 1) ret = ret * x;
		x = x * x;
	}
	return ret;
}

int main()
{
	int i, j, k;
	scanf("%d %d", &n, &m);
	for(i = 1; i <= n; i++)
	{
		scanf("%s", s + 1);
		insert();
	}
	make_fail();
	res.n = res.m = cnt;
	for(i = 0; i <= cnt; i++)
	{
		if(val[i]) continue;
		for(j = 0; j < 4; j++)
			if(!val[next[i][j]])
				res.a[i][next[i][j]]++;
	}
	res = res ^ m;
	for(i = 0; i <= cnt; i++)
		ans = (ans + res.a[0][i]) % p;
	printf("%d\n", ans);
	return 0;
}

  

时间: 2024-10-12 14:11:32

[POJ2778]DNA Sequence(AC自动机 + DP + 矩阵优化)的相关文章

[poj2778]DNA Sequence(AC自动机+矩阵快速幂)

解题关键:卡时限过的,正在找原因中. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cstdlib> 5 #include<cstring> 6 #include<iostream> 7 #include<queue> 8 using namespace std; 9 typedef long long ll; 10 cons

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

首先建立Trie和失败指针,然后你会发现对于每个节点 i 匹配AGCT时只有以下几种情况: i 节点有关于当前字符的儿子节点 j 且安全,则i 到 j找到一条长度为 1的路. i 节点有关于当前字符的儿子节点 j 且 不安全,则i 到 j没有路. i 节点没有关于当前字符的儿子节点 但是能通过失败指针找到一个安全的节点j,那么 i 到 j 找到一条长度为1的路. 关于节点安全的定义: 当前节点不是末节点且当前节点由失败指针指回跟节点的路径上不存在不安全节点,那么这个节点就是安全节点. 然后问题就

hdu 4878 ZCC loves words(AC自动机+dp+矩阵快速幂+中国剩余定理)

hdu 4878 ZCC loves words(AC自动机+dp+矩阵快速幂+中国剩余定理) 题意:给出若干个模式串,总长度不超过40,对于某一个字符串,它有一个价值,对于这个价值的计算方法是这样的,设初始价值为V=1,假如这个串能匹配第k个模式串,则V=V*prime[k]*(i+len[k]),其中prime[k]表示第k个素数,i表示匹配的结束位置,len[k]表示第k个模式串的长度(注意,一个字符串可以多次匹配同意个模式串).问字符集为'A'-'Z'的字符,组成的所有的长为L的字符串,

DNA Sequence(POJ2778 AC自动机dp+矩阵加速)

传送门 DNA Sequence Time Limit: 1000MS   Memory Limit: 65536K       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 sequenc

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

题目链接:poj 2778 DNA Sequence 题目大意:给定一些含有疾病的DNA序列,现在给定DNA长度,问有多少种不同的DNA序列是健康的. 解题思路:对DNA片段建立AC自动机,因为最多10个串,每个串最长为10,所以最多可能有100个节点,在长度为n时 以每个节点终止的健康字符串个数形成一个状态集,通过AC自动机形成的边可以推导出n+1的状态集,走到单词节点是 非法的,所以同样的我们可以先走到单词节点,但是从单词节点不向后转移.这样可以构造一个矩阵,剩下的就是矩阵 快速幂.注意的一

POJ2778 DNA Sequence AC自动机上dp

网址:https://vjudge.net/problem/POJ-2778 题意: 给出字符集${A,C,G,T}$和一些字符串(长度不超过$10$,且数量不超过$10$个),求长度为$n(n \leq 2e9)$的字符串中不包括上面这些字符串的字符串的数量. 题解: 我们可以先考虑一种方式:设$dp(i,j)$是用了$i$个字符拼出符合题意的长度为$j$的字符串的数量,在本题中$dp(i,j)=\sum _{j' \subseteq j} dp(i-1,j')$,显然时间复杂度是指数级的,不

POJ 2778 DNA Sequence (AC自动机,矩阵乘法)

题意:给定n个不能出现的模式串,给定一个长度m,要求长度为m的合法串有多少种. 思路:用AC自动机,利用AC自动机上的节点做矩阵乘法. 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<string> 6 #include<algorithm> 7 #include<queue> 8 #defin

Poj 2778 DNA Sequence (AC自动机+矩阵)

题目大意: 给出N个串,问在长度为L的所有串中,不包含任一已知串的个数有多少个. 思路分析: 已知一个矩阵A,A[i][j] 表示 节点i 到 节点 j 有一条变可以到达的方法数. 那么A^2 ,这个矩阵的 [i][j] 就代表这个节点 i 到节点 j 有两条边可以到达的方法数. 那么知道这个结论,我们要做的就是求一个节点到另外一个节点,要经过L条变(对应这长度为L的单词),而又要满足任意一条边都不能经过已知单词. 所以我们要用到ac自动机处理出所有已知的单词,在ac自动机上得到这个矩阵,使得任

POJ 3691 DNA repair AC自动机 + DP

题意:给你只包含‘A’,‘G’,‘T’,‘C’四个字母的n个模板串和1个文本串,问你文本串改变多少个字符就可以使得文本串中没有一个模板串 解题思路: 我们可以知道  dp[i][j] 为文本串到 第i 个字符  AC自动机状态为j的最少的变换次数(这里为什么要用AC自动机,因为end数组可以记录哪一个状态是结束的,而且处理以后可以知道那些后缀等于前缀--也就是不能到达,因为如果能够到达的话那么状态更新就会产生错误.),这样dp即可 解题代码: 1 // File Name: temp.cpp 2