1030: [JSOI2007]文本生成器 ac自动机+dp

https://www.lydsy.com/JudgeOnline/problem.php?id=1030

求长度为m不包含n个子串的种数,

跑完ac自动机之后没办法跑矩阵快速幂,因为状态数比较大(6000),所以dp转移,dp[i][j]表示前i个跑到j状态的不包含子串的情况数

//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pi acos(-1.0)
#define ll long long
#define vi vector<int>
//#define mod 1000000007
#define C 0.5772156649
#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pii pair<int,int>
#define cd complex<double>
#define ull unsigned long long
#define base 1000000000000000000
#define fio ios::sync_with_stdio(false);cin.tie(0)

using namespace std;

const double g=10.0,eps=1e-12;
const int N=6000+10,maxn=200000+10,inf=0x3f3f3f3f,INF=0x3f3f3f3f3f3f3f3f;

ll n,m,dp[110][N];
ll quick(ll a,ll b,ll c)
{
    ll ans=1;
    while(b)
    {
        if(b&1)ans=ans*a%c;
        a=a*a%c;
        b>>=1;
    }
    return ans;
}
char s[N];
struct ACM{
    int root,tot;
    int Next[N][30],fail[N],End[N];
    int newnode()
    {
        memset(Next[tot],-1,sizeof Next[tot]);
        End[tot]=0;
        return tot++;
    }
    ACM()
    {
        tot=0;
        root=newnode();
    }
    void ins()
    {
        int now=root,len=strlen(s);
        for(int i=0;i<len;i++)
        {
            if(Next[now][s[i]-'A']==-1)
                Next[now][s[i]-'A']=newnode();
            now=Next[now][s[i]-'A'];
        }
        End[now]=1;
    }
    void build()
    {
        queue<int>q;
        fail[root]=root;
        for(int i=0;i<26;i++)
        {
            if(Next[root][i]==-1)Next[root][i]=root;
            else
            {
                fail[Next[root][i]]=root;
                q.push(Next[root][i]);
            }
        }
        while(!q.empty())
        {
            int now=q.front();
            q.pop();
            if(End[fail[now]])End[now]=1;
            for(int i=0;i<26;i++)
            {
                if(Next[now][i]==-1)Next[now][i]=Next[fail[now]][i];
                else
                {
                    fail[Next[now][i]]=Next[fail[now]][i];
                    q.push(Next[now][i]);
                }
            }
        }
    }
    void solve()
    {
        dp[0][0]=1;
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<tot;j++)
            {
                if(!End[j]&&dp[i-1][j])
                {
                    for(int k=0;k<26;k++)
                    {
                        int now=j;
                        while(Next[now][k]==-1)now=fail[now];
                        dp[i][Next[now][k]]=(dp[i][Next[now][k]]+dp[i-1][j])%10007;
                    }
                }
            }
        }
        ll ans=quick(26,m,10007);
        for(int i=0;i<tot;i++)
            if(!End[i])
                ans=((ans-dp[m][i])%10007+10007)%10007;
        printf("%lld\n",ans);
    }
}ac;
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=0;i<n;i++)
    {
        scanf("%s",s);
        ac.ins();
    }
    ac.build();
    ac.solve();
    return 0;
}
/***********************

***********************/
View Code

 

posted @ 2018-04-27 20:48  walfy  阅读(195)  评论(0编辑  收藏  举报