zoukankan      html  css  js  c++  java
  • bzoj-1030(AC自动机+DP)

    题意:给你n个匹配串,算出所有长度为m且至少包括1个匹配串的数量;

    解题思路:首先根据题意,因为至少包括一个不好弄,根据容斥,我们可以把题目搞成求出所有长度为m不包括匹配串的字符串,然后减一下就是答案,求长度为m不包括有点像poj2778,但是因为状态太多,所有不能用矩阵,所以用dp解决,设dp【i】【j】表示当前第i个位置,且在trie图上j状态点的时候的数量。dp【i+1】【trie【j】【k】】+=dp【i】【j】;

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=10007;
    const int N=6050;
    int trie[N][26];
    int fail[N];
    int visit[N];
    int n,m,tot;
    int dp[110][N];
    char t[150];
    void build_trie(char *str)
    {
        int root=0;
        int len=strlen(str);
        for(int i=0;i<len;i++)
        {
            int id=str[i]-'A';
            if(!trie[root][id])
                trie[root][id]=++tot;
            root=trie[root][id];
        }
        visit[root]=1;
    }
    void build_fail()
    {
        queue<int>q;
        for(int i=0;i<26;i++)
            if(trie[0][i]!=0)
                q.push(trie[0][i]);
        while(!q.empty())
        {
            int now=q.front();q.pop();
            if(visit[fail[now]])
                visit[now]=1;
            for(int i=0;i<26;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]);
            }
        }
    }
    void init()
    {
        memset(fail,0,sizeof(fail));
        memset(trie,0,sizeof(trie));
        memset(visit,0,sizeof(visit));
        memset(dp,0,sizeof(dp));
        tot=0;
    }
    int solve()
    {
        dp[0][0]=1;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<=tot;j++)
            {
                if(visit[j])continue;
                for(int k=0;k<26;k++)
                {
                    if(visit[trie[j][k]])continue;
                    dp[i+1][trie[j][k]]=(dp[i+1][trie[j][k]]+dp[i][j])%mod;
                }
            }
        }
        int ans=1;int ans2=0;
        for(int i=1;i<=m;i++)
            ans=(ans*26)%mod;
        for(int i=0;i<=tot;i++)
            if(!visit[i])
            ans2=(ans2+dp[m][i])%mod;
        return (ans-ans2+mod)%mod;
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            init();
            for(int i=1;i<=n;i++)
            {
                scanf("%s",t);
                build_trie(t);
            }
            build_fail();
            cout<<solve()<<endl;
        }
    }
  • 相关阅读:
    常见二叉树问题
    leetcode上回溯法的使用
    搜索+回溯
    navicat连接登录windows10本地wsl的数据库
    皇后问题
    拓扑排序
    三路排序算法
    在 ServiceModel 客户端配置部分中,找不到引用协定“WebServiceTest.WebServiceSoap”的默认终结点元素。这可能是因为未找到应用程序的配置文件,或者是因为客户端元素
    WCF异常信息
    C# 制作ZIP压缩包
  • 原文地址:https://www.cnblogs.com/huangdao/p/10849233.html
Copyright © 2011-2022 走看看