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 #define MOD 100000
  9 char s[2005];
 10 int ch(char x){
 11     if (x==‘A‘) return 0;
 12     if (x==‘C‘) return 1;
 13     if (x==‘G‘) return 2;
 14     if (x==‘T‘) return 3;
 15     return -1;
 16 }
 17 struct Trie{
 18     int fail[1005],next[1005][5],end[1005],L,root;
 19     int newnode(){
 20         for (int i=0;i<4;i++)
 21          next[L][i]=-1;
 22         end[L++]=-1;
 23         return L-1;
 24     }
 25     void clear(){
 26          L=0;
 27          root=newnode();
 28     }
 29     void insert(char s[]){
 30         int len=strlen(s),now=root;
 31         for (int i=0;i<len;i++){
 32             if (next[now][ch(s[i])]==-1) next[now][ch(s[i])]=newnode();
 33             now=next[now][ch(s[i])];
 34         }
 35         end[now]=1;
 36     }
 37     void build(){
 38         std::queue<int>Q;
 39         int now;
 40         for (int i=0;i<4;i++)
 41          if (next[root][i]==-1)
 42           next[root][i]=root;
 43          else{
 44           fail[next[root][i]]=root;
 45           Q.push(next[root][i]);
 46          }
 47         while (!Q.empty()){
 48             now=Q.front();Q.pop();
 49             if (end[fail[now]]==1) end[now]=1;
 50             for (int i=0;i<4;i++){
 51                 if (next[now][i]==-1) next[now][i]=next[fail[now]][i];
 52                 else{
 53                     fail[next[now][i]]=next[fail[now]][i];
 54                     Q.push(next[now][i]);
 55                 }
 56             }
 57         }
 58     }
 59 }ac;
 60 struct Matrix{
 61     int n,mx[105][105];
 62     Matrix(){}
 63     Matrix(int x){
 64         n=x;
 65         for (int i=0;i<n;i++)
 66          for (int j=0;j<n;j++)
 67           mx[i][j]=0;
 68     }
 69 };
 70 Matrix operator *(Matrix a,Matrix b){
 71     int n=a.n;
 72     Matrix c=Matrix(n);
 73     for (int i=0;i<n;i++)
 74      for (int j=0;j<n;j++)
 75       for (int k=0;k<n;k++){
 76           int tmp=(long long) a.mx[i][k]*b.mx[k][j]%MOD;
 77           c.mx[i][j]=(c.mx[i][j]+tmp)%MOD;
 78       }
 79     return c;
 80 }
 81 Matrix powm(Matrix t,int m){
 82     Matrix r=Matrix(t.n);
 83     for (int i=0;i<=t.n;i++)
 84      r.mx[i][i]=1;
 85     while (m){
 86         if (m%2) r=r*t;
 87         t=t*t;
 88         m/=2;
 89     }
 90     return r;
 91 }
 92 int main(){
 93     int m;
 94     int n;
 95     while (scanf("%d%d",&n,&m)!=EOF){
 96         ac.clear();
 97         for (int i=0;i<n;i++){
 98             scanf("%s",s);
 99             ac.insert(s);
100         }
101         ac.build();
102         Matrix a=Matrix(ac.L);
103         for (int i=0;i<ac.L;i++)
104           for (int j=0;j<4;j++)
105             if (ac.end[ac.next[i][j]]==-1)
106                 a.mx[i][ac.next[i][j]]++;
107         a=powm(a,m);
108         int ans=0;
109         for (int i=0;i<a.n;i++)
110          ans=(ans+a.mx[0][i])%MOD;
111         printf("%d\n",ans);
112     }
113 }
时间: 2024-10-03 19:02:21

POJ 2778 DNA Sequence (AC自动机,矩阵乘法)的相关文章

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

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

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

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

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

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

POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂

这两题属于AC自动机的第二种套路通过矩阵快速幂求方案数. 题意:给m个病毒字符串,问长度为n的DNA片段有多少种没有包含病毒串的. 根据AC自动机的tire图,我们可以获得一个可达矩阵. 关于这题的tire图详解可以点击这里,往下面翻,这个博主的图对于tire图讲的非常详细. 知道了什么是tire图,理解了tire图后,后面的AC自动机的题目才能写. AC自动机的灵魂应该就是tire图 然后问题就变成了,得到了一个可达矩阵后,如何求方案数呢? 这个n = 2000000000 这咋办呢? 给定一

[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

poj2778DNA Sequence(AC自动机+矩阵乘法)

链接 看此题前先看一下matrix67大神写的关于十个矩阵的题目中的一个,如下: 经典题目8 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值    把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j.令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点).类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数.同理,如果要求经过k步的路径数,我们只需要二分求出A^k

BZOJ 1009 [HNOI2008]GT考试 AC自动机+矩阵乘法

题意:链接略 方法: AC自动机+矩阵乘法 解析: 和POJ 2778 一样的题. 大概的思路就是我们建AC自动机的时候需要注意如果某个点是一个串的结尾的话,那么下面的节点都要看成结尾节点. 然后按照AC自动机赋一下矩阵内部值就好了. 赋的矩阵代表从一个节点走一步走到另一个节点有多少方案. 然后经典模型,矩阵的n次方即可. 代码: #include <queue> #include <cstdio> #include <cstring> #include <ios

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

题目链接:DNA Sequence 解析:AC自动机 + 矩阵加速(快速幂). 这个时候AC自动机 的一种状态转移图的思路就很透彻了,AC自动机就是可以确定状态的转移. AC代码: #include <iostream> #include <cstdio> #include <queue> #include <cstring> using namespace std; const int MOD = 100000; struct Matrix{ int ma

POJ 2778 DNA Sequence(AC自动机确定DFA转移图+矩阵快速幂)

这道题极好的展示了AC自动机在构造转移图DFA上的应用 DFA转移图就是展示状态的转移过程的图,DFA图构造出来后就可以用DP求出任何DNA长度下,任何状态的个数 本题用自动机求出DFA矩阵,那么有 | dp[n][0] dp[n][1] ... dp[n][m] |=|dp[1][0] dp[1][1] ... dp[1][m] | * DFA^(n-1)    (m指状态总数) DP边界矩阵|dp[1][0] dp[1][1] ... dp[1][m] | 也就是DFA的第一行,所以dp[n