POJ 2778 AC自动机+矩阵幂 不错的题

http://poj.org/problem?id=2778

有空再重新做下,对状态图的理解很重要

题解:

http://blog.csdn.net/morgan_xww/article/details/7834801

另外做了矩阵幂的模板:

//ac.sz是矩阵的大小
void mulmtr(long long x[MAXNODE][MAXNODE],long long y[MAXNODE][MAXNODE])//y=x*y
{
    ll tmp[MAXNODE][MAXNODE];
    for(int i=0;i<ac.sz;i++)
    {
        for(int j=0;j<ac.sz;j++)
        {
            tmp[i][j]=0;
            for(int k=0;k<ac.sz;k++)
                tmp[i][j] +=x[i][k]*y[k][j];
            tmp[i][j] %=MOD;
        }
    }
    for(int i=0;i<ac.sz;i++)
        for(int j=0;j<ac.sz;j++)
            y[i][j]=tmp[i][j];
}
void Mtrmi(ll mtr[MAXNODE][MAXNODE],int n)
{
    for(int i=0;i<ac.sz;i++)
    {
        for(int j=0;j<ac.sz;j++)
        {
            if(i == j)ans[i][j]=1;//E矩阵
            else ans[i][j]=0;
        }
    }
    while(n)
    {
        if(n&1)
        {
            mulmtr(mtr,ans);
        }
        mulmtr(mtr,mtr);
        n/=2;
    }
}

代码:

#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <queue>
#include <iostream>
using namespace std;

#define ll long long

const int MAXNODE  = 15*15;
const int SSIZE  = 2000000000+100;
const int MOD = 100000;
const int SIGMA_SIZE = 4;
const int SIZE = 20;

ll mtr[MAXNODE][MAXNODE];
ll ans[MAXNODE][MAXNODE];
int danger[MAXNODE];

struct AC
{
    int f[MAXNODE];
    int val[MAXNODE];
    int last[MAXNODE];
    int cnt[MAXNODE];
    int ch[MAXNODE][SIGMA_SIZE];
    int sz;

    void init()
    {
        memset(ch[0],0,sizeof(ch[0]));
        memset(cnt,0,sizeof(cnt));
        f[0]=0;///////////
        sz=1;
    }

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

    void insert(char *s, int v)
    {
        int n=strlen(s),u=0;
        for(int i=0;i<n;i++)
        {
            int id= idx(s[i]);
            if(!ch[u][id])
            {
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                ch[u][id]=sz++;
            }
            u=ch[u][id];
        }
        val[u]=v;
        danger[u]=1;////////
    }

    void getfail()
    {
        queue<int>q;
        f[0]=0;
        for(int c=0;c<SIGMA_SIZE;c++)
        {
            int u=ch[0][c];
            if(u)
            {
                q.push(u);
                f[u]=0;
                last[u]=0;
            }
        }
        while(!q.empty())
        {
            int r=q.front();q.pop();
            for(int c=0;c<SIGMA_SIZE;c++)
            {
                int u=ch[r][c];
                //if(!u)continue;////////
                if(!u)
                {
                    ch[r][c]=ch[f[r]][c];//////
                    continue;
                }
                q.push(u);
                int v=f[r];
                while(v &&!ch[v][c])v=f[v];
                f[u]=ch[v][c];
                //last[u]=val[f[u]]?f[u]:last[f[u]];
                danger[u] |= danger[f[u]];
            }
        }
    }
};
void init()
{
    memset(mtr,0,sizeof(mtr));
    memset(danger,0,sizeof(danger));
}

AC ac;

char str[SIZE];

void mulmtr(long long x[MAXNODE][MAXNODE],long long y[MAXNODE][MAXNODE])//y=x*y
{
    ll tmp[MAXNODE][MAXNODE];
    for(int i=0;i<ac.sz;i++)
    {
        for(int j=0;j<ac.sz;j++)
        {
            tmp[i][j]=0;
            for(int k=0;k<ac.sz;k++)
                tmp[i][j] +=x[i][k]*y[k][j];
            tmp[i][j] %=MOD;
        }
    }
    for(int i=0;i<ac.sz;i++)
        for(int j=0;j<ac.sz;j++)
            y[i][j]=tmp[i][j];
}
void Mtrmi(ll mtr[MAXNODE][MAXNODE],int n)
{
    for(int i=0;i<ac.sz;i++)
    {
        for(int j=0;j<ac.sz;j++)
        {
            if(i == j)ans[i][j]=1;//E矩阵
            else ans[i][j]=0;
        }
    }
    while(n)
    {
        if(n&1)
        {
            mulmtr(mtr,ans);
        }
        mulmtr(mtr,mtr);
        n/=2;
    }
}

int main()
{
    //freopen("poj2788.txt","r",stdin);
    int n,m;
    while(~scanf("%d%d",&m,&n))
    {
        init();
        ac.init();
        for(int i=1;i<=m;i++)
        {
            scanf("%s",str);
            ac.insert(str,i);
        }
        ac.getfail();
        for(int i=0;i<ac.sz;i++)
            if(!danger[i])
                for(int j=0;j<4;j++)
                    if(!danger[ac.ch[i][j]])
                    {
                        mtr[i][ac.ch[i][j]]++;
                    }

        Mtrmi(mtr,n);
                /////////////////////////////////
       /* for(int i=0;i<ac.sz;i++)
        {
            for(int j=0;j<ac.sz;j++)
                printf("%lld|%lld ",mtr[i][j],ans[i][j]);
            putchar('\n');
        }*/
        ///////////////////////
        for(int i=1;i<ac.sz;i++)
            ans[0][0]+=ans[0][i]%MOD;
        printf("%I64d\n",ans[0][0]%MOD);
    }
    return 0;
}

POJ 2778 AC自动机+矩阵幂 不错的题

时间: 2024-12-27 17:26:40

POJ 2778 AC自动机+矩阵幂 不错的题的相关文章

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

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

DNA Sequence POJ - 2778 AC 自动机 矩阵乘法

定义重载运算的时候一定要将矩阵初始化,因为这个调了一上午...... Code: #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<string> #define maxn 100000 typedef long long ll; using namespace std; void setIO(string a){ freopen((a+

poj 2778 AC自动机与矩阵连乘

http://poj.org/problem?id=2778 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

poj 2778 AC自动机构建有向图 + 邻接矩阵快速幂

Problem: 给你m个病毒串,求指定长度n且不含病毒串作为子串的字符串一共有多少种. Analyse: 用AC自动机构建L个状态节点,每个节点的end标记记录是否在这里形成病毒串. 这里有个核心就是,如果当前后缀的子后缀(也就是它的fail指针指向的地方)是病毒串的话, 那么它就是病毒串. 然后根据这个AC自动机的L个节点来建立有向图的邻接矩阵B,B[i][j]代表从i到j状态的路径数量. B[0][j]代表的是从初始状态,还没有任何字符的时候转移到j状态,因为根节点0就是没有任何限制. 然

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

题目链接: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 AC自己主动机 + 矩阵高速幂

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

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

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

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

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