poj2778 ac自动机+矩阵快速幂

给m个子串,求长度为n的不包含子串的母串数,最直接的应该是暴搜,肯定tle,考虑用ac自动机

将子串建成字典树,通过next表来构造矩阵,然后用矩阵快速幂求长度为n的数量

邻接矩阵https://wenku.baidu.com/view/d7b9787f1711cc7931b716b0.html

对于a(i,j)^k  是指从i到j经过k个点的所有情况数

注意对于End数组,如果某个节点如果fail指针End数组为1,那么End【该节点】也是1

string要开全局变量,不然不能运行= =

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<iomanip>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define C 0.5772156649
#define pi acos(-1.0)
#define ll long long
#define mod 100000
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1

using namespace std;

const double g=10.0,eps=1e-7;
const int N=100+10,maxn=100+10,inf=0x3f3f3f;

struct Node{
    int len;
    ll a[N][N];
};
Node mul(Node x,Node y)
{
    Node ans;
    ans.len=x.len;
    memset(ans.a,0,sizeof ans.a);
    for(int i=0;i<x.len;i++)
        for(int j=0;j<x.len;j++)
            for(int k=0;k<y.len;k++)
                ans.a[i][k]=(ans.a[i][k]+x.a[i][j]*y.a[j][k])%mod;
    return ans;
}
Node quick_mul(Node x,int n)
{
    Node ans;
    ans.len=x.len;
    memset(ans.a,0,sizeof ans.a);
    for(int i=0;i<ans.len;i++)ans.a[i][i]=1;
    while(n)
    {
        if(n&1)ans=mul(ans,x);
        x=mul(x,x);
        n/=2;
    }
    return ans;
}
struct Trie{
    int tot,root;
    int Next[N][4],fail[N];
    bool End[N];
    int change(char s)
    {
        if(s==‘A‘)return 0;
        else if(s==‘C‘)return 1;
        else if(s==‘T‘)return 2;
        else return 3;
    }
    int newnode()
    {
        for(int i=0;i<4;i++)
            Next[tot][i]=-1;
        End[tot]=0;
        return tot++;
    }
    void init()
    {
        tot=0;
        root=newnode();
    }
    void insertstring(string s)
    {
        int now=root;
        for(int i=0;i<s.size();i++)
        {
            if(Next[now][change(s[i])]==-1)
                Next[now][change(s[i])]=newnode();
            now=Next[now][change(s[i])];
        }
        End[now]=1;
    }
    void build()
    {
        queue<int>q;
        fail[root]=root;
        for(int i=0;i<4;i++)
        {
            if(Next[root][i]==-1)Next[root][i]=root;
            else
            {
                fail[Next[root][i]]=root;
                q.push(Next[root][i]);
            }
        }
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            if(End[fail[now]])End[now]=1;
            for(int i=0;i<4;i++)
            {
                if(Next[now][i]==-1)Next[now][i]=Next[fail[now]][i];
                else
                {
                    fail[Next[now][i]]=Next[fail[now]][i];
                    q.push(Next[now][i]);
                }
            }
        }
    }
    int solve(int n)
    {
        Node ans;
        ans.len=tot;
        memset(ans.a,0,sizeof ans.a);
        for(int i=0;i<tot;i++)
            for(int j=0;j<4;j++)
                if(!End[Next[i][j]])
                    ans.a[i][Next[i][j]]++;
        ans=quick_mul(ans,n);
        int res=0;
        for(int i=0;i<ans.len;i++)
            res=(res+(int)ans.a[0][i])%mod;
        return res;
    }
};
Trie ac;
string s;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    while(cin>>m>>n)
    {
        ac.init();
        for(int i=0;i<m;i++)
        {
            cin>>s;
            ac.insertstring(s);
        }
        ac.build();
        cout<<ac.solve(n)<<endl;
    }
    return 0;
}
/********************

********************/

时间: 2025-01-01 11:47:52

poj2778 ac自动机+矩阵快速幂的相关文章

hdu 2243 AC自动机 + 矩阵快速幂

// hdu 2243 AC自动机 + 矩阵快速幂 // // 题目大意: // // 给你一些短串,问在长度不超过k的任意串,包含至少一个这些短串的其中 // 一个.问这样的串有多少个. // // 解题思路: // // 首先, 包含和不包含是一种互斥关系,包含+不包含 = 全集u.全集的答案就是 // 26 ^ 1 + 26 ^ 2 + .... + 26 ^ k.不包含的比较好求.构建一个自动机,得到 // 一个转移矩阵A.表示状态i能到状态j的方法数.而这些状态中都是不包含所给的 //

HDU 2243 考研路茫茫――单词情结 (AC自动机 + 矩阵快速幂)

题目链接:考研路茫茫――单词情结 做本题前,个人建议先做一下POJ 2778 http://blog.csdn.net/u013446688/article/details/47378255 POJ2778 是求长度为n,不包含模式串的字符串个数. 而本题是求长度为n,包含模式串的字符串个数.直接用字符串总数减去不包含模式串的字符串个数即为所求. 同样是AC自动机 + 矩阵快速幂.但是还是有所不同的. 因为对2^64取模,所以定义数据类型为unsigned long long就可以了,这样就实现

poj 2778 AC自动机 + 矩阵快速幂

// poj 2778 AC自动机 + 矩阵快速幂 // // 题目链接: // // http://poj.org/problem?id=2778 // // 解题思路: // // 建立AC自动机,确定状态之间的关系,构造出,走一步 // 能到达的状态矩阵,然后进行n次乘法,就可以得到状态间 // 走n步的方法数. // 精髓: // 1):这个ac自动机有一些特别,根节点是为空串,然而 // 每走一步的时候,如果没法走了,这时候,不一定是回到根 // 节点,因为有可能单个的字符时病毒,这样

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

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

HDU 2243 考研路茫茫――单词情结 ——(AC自动机+矩阵快速幂)

和前几天做的AC自动机类似. 思路简单但是代码200余行.. 假设solve_sub(i)表示长度为i的不含危险单词的总数. 最终答案为用总数(26^1+26^2+...+26^n)减去(solve_sub(1)+solve(2)+...+solve_sub(n)).前者构造f[i]=f[i-1]*26+26然后矩阵快速幂即可(当然也可以分治的方法).后者即构造出dp矩阵p,然后计算(p^1+p^2+...+p^n),对其分治即可. 代码如下: 1 #include <stdio.h> 2 #

poj2778DNA Sequence (AC自动机+矩阵快速幂)

转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud 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 DN

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自动机 + 矩阵快速幂)

题目链接: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

HDU 2243考研路茫茫——单词情结 (AC自动机+矩阵快速幂)

背单词,始终是复习英语的重要环节.在荒废了3年大学生涯后,Lele也终于要开始背单词了. 一天,Lele在某本单词书上看到了一个根据词根来背单词的方法.比如"ab",放在单词前一般表示"相反,变坏,离去"等. 于是Lele想,如果背了N个词根,那这些词根到底会不会在单词里出现呢.更确切的描述是:长度不超过L,只由小写字母组成的,至少包含一个词根的单词,一共可能有多少个呢?这里就不考虑单词是否有实际意义. 比如一共有2个词根 aa 和 ab ,则可能存在104个长度不