• poj2778(AC自动机+矩阵快速幂)


    题意:给你n个字符串,问你长度为m的字符串且字符串中不含有那n个子串的字符串的数量

    解题思路:这道题一开始就不太懂,还以为是组合数学的题目,后面看了别人的博客,才知道这是属于AC自动机的另一种用法,是关于fail数组的运用,因为题目问的是不允许包含那n个字符串,所以我们可以这么想,假设一个trie树每个结点都有A,T,C,G这四个儿子结点,然后我们把这n个字符串存进trie树里面,字符串的结尾标记一下,然后根据fail数组的构造,如果某个结点fail指向的结点被标记了,那么这个结点也是不允许走的,这样,一个符合条件的trie树就建立出来了,剩下的就是矩阵部分。把题目简化成是从结点0出发到其他结点走n步的的所有允许情况;

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int N=110;
    struct matrix
    {
        ll mat[N][N];
        matrix()
        {
            memset(mat,0,sizeof(mat));
        }
    }ans,fna;
    int trie[N][4];
    int fail[N],tot;
    bool flag[N];
    char s[15];
    char c['Z'+1];
    int n,m;
    void build_trie(char *str)//构建trie树
    {
        int root=0;
        int len=strlen(str);
        for(int i=0;i<len;i++)
        {
            int id=c[str[i]];
            if(trie[root][id]==0)
            {
                trie[root][id]=++tot;
                //cout<<tot<<endl;
            }
            root=trie[root][id];
        }
        flag[root]=1;
    }
    void build_fail()
    {
        queue<int>q;
        for(int i=0;i<4;i++)
        {
            if(trie[0][i]!=0)
                q.push(trie[0][i]);
        }
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            if(flag[fail[now]])//如果当前结点的指向是不允许的,那么这个点也是不允许的
                flag[now]=true;
            for(int i=0;i<4;i++)
            {
                if(!trie[now][i])
                {
                    trie[now][i]=trie[fail[now]][i];
                    continue;
                }
                fail[trie[now][i]]=trie[fail[now]][i];
                q.push(trie[now][i]);
            }
        }
    }
    matrix mul(matrix x,matrix y)
    {
        matrix tmp;
        for(int i=0;i<=tot;i++)
            for(int j=0;j<=tot;j++)
                for(int k=0;k<=tot;k++)
        {
            tmp.mat[i][j]+=x.mat[i][k]*y.mat[k][j];
            tmp.mat[i][j]%=100000;
        }
        return tmp;
    }
    matrix matrixpow(matrix x,ll k)
    {
        matrix ret;
        for(int i=0;i<=tot;i++)
            ret.mat[i][i]=1;
        while(k)
        {
            if(k&1)
                ret=mul(ret,ans);
            ans=mul(ans,ans);
            k>>=1;
        }
        return ret;
    }
    matrix build_mat()//构建矩阵
    {
        matrix temp;
        for(int i=0;i<=tot;i++)
        {
            if(flag[i])
                continue;
            for(int j=0;j<4;j++)
            {
                if(flag[trie[i][j]])continue;
                ++temp.mat[i][trie[i][j]];
            }
        }
        return temp;
    }
    void init()
    {
        memset(fail,0,sizeof(fail));
        memset(trie,0,sizeof(trie));
        tot=0;
        memset(flag,0,sizeof(flag));
        c['A']=0;
        c['T']=1;
        c['C']=2;
        c['G']=3;
    }
    int main()
    {
        init();
        scanf("%d%d",&m,&n);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",s);
            build_trie(s);
        }
        build_fail();
        ans=build_mat();
        fna=matrixpow(ans,n);
        ll xx=0;
        for(int i=0;i<=tot;i++)
        {
            xx+=fna.mat[0][i];xx%=100000;
        }
        printf("%lld
    ",xx);
    }
    

      

    代码:

  • 相关阅读:
    IOS -- 获取本地图片和网络图片的大小size
    xib中的label加边框
    iOS开发之Masonry框架源码深度解析
    10分钟搭建 App 主流框架
    卸载服务器GitLab
    linux安装git方法
    虚拟机安装centos7, 再安装gitlab 简单步骤
    collectionView 防止cell复用的方法
    UIButton 设置图片文字垂直居中排列
    button获取验证码60秒倒计时 直接用
  • 原文地址:https://www.cnblogs.com/huangdao/p/9931308.html
Copyright © 2020-2023  润新知