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;
    }
}

 

posted @ 2019-05-11 17:02  荒岛的龟  阅读(159)  评论(0编辑  收藏