poj 2778 经典 AC自动机+dp

23 篇文章 0 订阅
12 篇文章 0 订阅

http://blog.henix.info/blog/poj-2778-aho-corasick-dp.html 讲得很好

1.当要转移的次数很多,有牵涉到很多关系时,用矩阵

2.fail指针的理解

用数组的写法更容易理解,抄师兄的代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define mod 100000
#define CH 4
#define maxnode 110
#define ll long long
int ch[maxnode][CH],val[maxnode],fail[maxnode],que[maxnode*2],sz;
int sw[300];
int m,n;
void _insert(char *str)
{
    int u=0,len=strlen(str);
    for(int i=0;i<len;++i)
    {
        if(!ch[u][sw[str[i]]])
        {
            val[sz]=0;
            memset(ch[sz],0,sizeof(ch[sz]));
            ch[u][sw[str[i]]]=sz++;
        }
        u=ch[u][sw[str[i]]];
    }
    val[u]=1;
}
void getfail()
{
    int front=0,rear=0;
    for(int i=0;i<CH;++i)
        if(ch[0][i])
    {
        fail[ch[0][i]]=0;
        que[rear++]=ch[0][i];
    }
    while(front<rear)
    {
        int u=que[front++];
        for(int i=0;i<CH;++i)
        {
            if(ch[u][i])
            {
                que[rear++]=ch[u][i];
                fail[ch[u][i]]=ch[fail[u]][i];
                val[ch[u][i]] |= val[ch[fail[u]][i]];
            }
            else ch[u][i]=ch[fail[u]][i];
            // 把不存在的边也补上,就能对所有转移都一视同仁
            // 不再 while(j&&str[ch[v][i]]!=str[ch[u][i]]) v=f[v]
        }
    }
}
struct matrix
{
    int n;
    ll m[110][110];
    matrix(int _n=0){n=_n;memset(m,0,sizeof(m));}
    matrix operator*(matrix &r)
    {
        matrix t(n);
        for(int i=0;i<n;++i)
            for(int j=0;j<n;++j)
        {
            t.m[i][j]=0;
            for(int k=0;k<n;++k)
            {
                t.m[i][j]+=m[i][k]*r.m[k][j];
                if(t.m[i][j]>=mod)
                    t.m[i][j]%=mod;
            }
        }
        return t;
    }
};
void getmatrix(matrix &a)
{
    for(int i=0;i<sz;++i)
        if(!val[i])
    {
        for(int j=0;j<CH;++j)
            if(!val[ch[i][j]])
            {
                a.m[i][ch[i][j]]++;
            }
    }
}
char str[100];
int main ()
{
    // initialize
    memset(ch[0],0,sizeof(ch[0]));
    sz=1;
    // 压缩sigma_size
    sw['A']=0;sw['G']=1;sw['T']=2;sw['C']=3;

    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;++i)
    {
        scanf("%s",str);
        _insert(str);
    }
    getfail();
    matrix a(sz),res(sz);
    for(int i=0;i<sz;++i)
        res.m[i][i]=1;
    getmatrix(a);
    while(n)
    {
        if(n&1) res=res*a;
        n>>=1;
        a=a*a;
    }
    ll ans=0;
    for(int i=0;i<sz;++i)
    {
        ans+=res.m[0][i];
        if(ans>=mod) ans%=mod;
    }
    cout<<ans<<endl;
    return 0;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值