POJ 2778 DNA Sequence —— (AC自动机+矩阵快速幂)
距离上次做AC自动机有很久了=。=,以前这题的思路死活看不懂,现在还是觉得很好理解的。
思路参见:http://blog.csdn.net/morgan_xww/article/details/7834801#。
我用cnt=1表示这个节点是危险的,然后再匹配fail指针的时候,如果一个节点的前缀是危险的,那么这个节点也是危险的,这么维护即可。
顺便一提,我以前的AC自动机模板是没有build过程中失配时的nxt指针的(以前是在match的过程中体现),但是失败时候需要的nxt指针又是很好用的,因此以后的模板中在build中新增这个内容(其实上次的AC自动机DP中就已经有了)。
另外两点可能不是很重要的是:1.我的矩阵模板统一是从1开始的,而这里有0节点;2.在结构体内似乎不能直接初始化字符串= =。
代码如下(我的代码跑的有点慢。。):
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <queue>
using namespace std;
const int MAX_Tot = + ;
const int mod = ; int m,n; void add(int &a,int b)
{
a += b;
if(a < ) a += mod;
a %= mod;
} struct matrix
{
int e[MAX_Tot][MAX_Tot],n,m;
matrix() {}
matrix(int _n,int _m): n(_n),m(_m) {memset(e,,sizeof(e));}
matrix operator * (const matrix &temp)const
{
matrix ret = matrix(n,temp.m);
for(int i=;i<=ret.n;i++)
{
for(int j=;j<=ret.m;j++)
{
for(int k=;k<=m;k++)
{
add(ret.e[i][j],1LL*e[i][k]*temp.e[k][j]%mod);
}
}
}
return ret;
}
matrix operator + (const matrix &temp)const
{
matrix ret = matrix(n,m);
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
add(ret.e[i][j],(e[i][j]+temp.e[i][j])%mod);
}
}
return ret;
}
void getE()
{
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
e[i][j] = i==j?:;
}
}
}
}; matrix qpow(matrix temp,int x)
{
int sz = temp.n;
matrix base = matrix(sz,sz);
base.getE();
while(x)
{
if(x & ) base = base * temp;
x >>= ;
temp = temp * temp;
}
return base;
} char way[] = {'A','T','C','G'};
struct Aho
{
struct state
{
int nxt[];
int fail,cnt;
}stateTable[MAX_Tot]; int find(char c) {for(int i=;i<;i++) if(c == way[i]) return i;} int size; queue<int> que; void init()
{
while(que.size()) que.pop();
for(int i=;i<MAX_Tot;i++)
{
memset(stateTable[i].nxt,,sizeof(stateTable[i].nxt));
stateTable[i].fail = stateTable[i].cnt = ;
}
size = ;
} void insert(char *s)
{
int n = strlen(s);
int now = ;
for(int i=;i<n;i++)
{
char c = s[i];
int to = find(c);
if(!stateTable[now].nxt[to])
stateTable[now].nxt[to] = size++;
now = stateTable[now].nxt[to];
}
stateTable[now].cnt = ;
} void build()
{
stateTable[].fail = -;
que.push(); while(que.size())
{
int u = que.front();que.pop();
for(int i=;i<;i++)
{
if(stateTable[u].nxt[i])
{
if(u == ) stateTable[stateTable[u].nxt[i]].fail = ;
else
{
int v = stateTable[u].fail;
while(v != -)
{
if(stateTable[v].nxt[i])
{
stateTable[stateTable[u].nxt[i]].fail = stateTable[v].nxt[i];
// 在匹配fail指针的时候顺便更新cnt
if(stateTable[stateTable[stateTable[u].nxt[i]].fail].cnt == )
stateTable[stateTable[u].nxt[i]].cnt = ;
break;
}
v = stateTable[v].fail;
}
if(v == -) stateTable[stateTable[u].nxt[i]].fail = ;
}
que.push(stateTable[u].nxt[i]);
}
/*****建立自动机nxt指针*****/
else
{
if(u == ) stateTable[u].nxt[i] = ;
else
{
int p = stateTable[u].fail;
while(p != - && stateTable[p].nxt[i] == ) p = stateTable[p].fail;
if(p == -) stateTable[u].nxt[i] = ;
else stateTable[u].nxt[i] = stateTable[p].nxt[i];
}
}
/*****建立自动机nxt指针*****/
}
}
} matrix build_matrix()
{
matrix ans = matrix(size,size);
for(int i=;i<size;i++)
{
for(int j=;j<;j++)
{
if(!stateTable[i].cnt && !stateTable[stateTable[i].nxt[j]].cnt)
ans.e[i+][stateTable[i].nxt[j]+]++;
}
}
return ans;
}
}aho; int main()
{
while(scanf("%d%d",&m,&n) == )
{
aho.init();
char s[];
for(int i=;i<=m;i++)
{
scanf("%s",s);
aho.insert(s);
}
aho.build();
matrix p = aho.build_matrix();
p = qpow(p,n);
int ans = ;
for(int i=;i<=aho.size;i++) add(ans, p.e[][i]);
printf("%d\n",ans);
}
return ;
}
POJ 2778 DNA Sequence —— (AC自动机+矩阵快速幂)的更多相关文章
- poj 2778 DNA Sequence ac自动机+矩阵快速幂
链接:http://poj.org/problem?id=2778 题意:给定不超过10串,每串长度不超过10的灾难基因:问在之后给定的长度不超过2e9的基因长度中不包含灾难基因的基因有多少中? DN ...
- POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂
这两题属于AC自动机的第二种套路通过矩阵快速幂求方案数. 题意:给m个病毒字符串,问长度为n的DNA片段有多少种没有包含病毒串的. 根据AC自动机的tire图,我们可以获得一个可达矩阵. 关于这题的t ...
- POJ 2778 DNA Sequence (AC自动机,矩阵乘法)
题意:给定n个不能出现的模式串,给定一个长度m,要求长度为m的合法串有多少种. 思路:用AC自动机,利用AC自动机上的节点做矩阵乘法. #include<iostream> #includ ...
- [poj2778]DNA Sequence(AC自动机+矩阵快速幂)
题意:有m种DNA序列是有疾病的,问有多少种长度为n的DNA序列不包含任何一种有疾病的DNA序列.(仅含A,T,C,G四个字符) 解题关键:AC自动机,实际上就是一个状态转移图,注意能少取模就少取模, ...
- poj2778 DNA Sequence(AC自动机+矩阵快速幂)
Description It's well known that DNA Sequence is a sequence only contains A, C, T and G, and it's ve ...
- POJ 2778 DNA Sequence ( AC自动机、Trie图、矩阵快速幂、DP )
题意 : 给出一些病毒串,问你由ATGC构成的长度为 n 且不包含这些病毒串的个数有多少个 分析 : 这题搞了我真特么久啊,首先你需要知道的前置技能包括 AC自动机.构建Trie图.矩阵快速幂,其中矩 ...
- POJ 2778 DNA Sequence (AC自动机+DP+矩阵)
题意:给定一些串,然后让你构造出一个长度为 m 的串,并且不包含以上串,问你有多少个. 析:很明显,如果 m 小的话 ,直接可以用DP来解决,但是 m 太大了,我们可以认为是在AC自动机图中,根据离散 ...
- poj2778DNA Sequence (AC自动机+矩阵快速幂)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud DNA Sequence Time Limit: 1000MS Memory ...
- poj 2778 DNA Sequence AC自动机DP 矩阵优化
DNA Sequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11860 Accepted: 4527 Des ...
- poj 2778 DNA Sequence AC自动机
DNA Sequence Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 11860 Accepted: 4527 Des ...
随机推荐
- Java数据结构HashMap
java数据结构HashMap /** * <html> * <body> * <P> Copyright JasonInternational</p> ...
- SQL Server系统函数:类型转换函数
原文:SQL Server系统函数:类型转换函数 1.基本的转化 SELECT CAST(2008 as varchar(4)) + ' year!' SELECT CONVERT(varchar(4 ...
- springboot启动流程(十二)springboot事务自动配置
所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 正文 在上一篇文章中,我们简单了解了aop的处理过程.代理增强之前,先生成Advisor,然后 ...
- Python多个装饰器的顺序 转载
3.使用两个装饰器当一个装饰器不够用的话,我们就可以用两个装饰器,当然理解起来也就更复杂了,当使用两个装饰器的话,首先将函数与内层装饰器结合然后在与外层装饰器相结合,要理解@语法的时候到底执行了什么, ...
- js大数计算之计算
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- eclipse调试之edit source lookup path解决方案
转自:https://blog.csdn.net/zkn_CS_DN_2013/article/details/48731133
- leetcode-88. 合并两个有序数组 · Aaray
题面 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 样例 1. 输入: nums1 = [1,2,3,0,0,0], m ...
- 理解JVM之JAVA运行时内存区域
java运行时内存区域划分为方法区,堆区,虚拟机栈区,本地方法栈,程序计数器.其中方法区跟堆区是线程共享的数据区,其他的是线程私有的数据区. 1.程序计数器 程序计数器(PC)是一块较小的内存,他是存 ...
- MacOS文本编辑无法打不开GB18030
不要直接双击打开 而是 打开sublime text或者其他文本编辑后,从软件里面的open选型打开
- php+redis一步一步测试秒杀
1.普通的秒杀查库减库存: <?php /** 100个用户同时访问100次会出现超卖 **/ //连接数据库 $dsn = "mysql:host=localhost;dbname= ...