bzoj1030: [JSOI2007]文本生成器

mdzz调了一中午。。

用了解的单词建AC自动机

原问题显然不太好搞啊。。

那么转换一下sum-不包含了解单词的文本数

问题变成在AC机上走m步不到达ed节点的方案数

变成DP: f[i][j]表示走到第i个节点,走了j步

宽搜转移一下。

坑点就是了解的单词有一个是另一个的字串就会减多

这样的话要把fail全部跳一次

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int mod=10007;
int MOD(int x){return (x%mod+mod)%mod;}

struct Trie
{
    int w[30],fail;
    bool ed;
    void clean(){memset(w,0,sizeof(w));fail=0;ed=false;}
}tr[11000];int trlen;
char ss[110];
void maketree()
{
    int now=0,len=strlen(ss+1);
    for(int i=1;i<=len;i++)
    {
        int x=ss[i]-'A'+1;
        if(tr[now].w[x]==0)
            tr[now].w[x]=++trlen, tr[trlen].clean();
        now=tr[now].w[x];
    }
    tr[now].ed=true;
}

int q[11000];
void bfs()
{
    int head=1,tail=2;q[1]=0;
    while(head!=tail)
    {
        int now=q[head];
        for(int x=1;x<=26;x++)
        {
            int son=tr[now].w[x];
            if(son!=0)
            {
                if(now==0)tr[son].fail=0;
                else
                {
                    int p=tr[now].fail;
                    while(p!=0&&tr[p].w[x]==0)p=tr[p].fail;
                    tr[son].fail=tr[p].w[x];
                }
                q[tail]=son;
                tail++;
            } 
        }
        head++;
    }
}

//-------------AC_machine--------------

struct node
{
    int now,uh;
}list[1100000];
bool v[11000][110];
int f[11000][110];
int main()
{
    freopen("generator.in","r",stdin);
    freopen("generator.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%s",ss+1),maketree();
    bfs();
    
    memset(f,0,sizeof(f));f[0][0]=1;
    memset(v,false,sizeof(v));v[0][0]=true;
    int head=1,tail=2,ans=0;
    list[1].now=0;list[1].uh=0;
    while(head!=tail)
    {
        int now=list[head].now,uh=list[head].uh;head++;
        if(uh==m){ans=MOD(ans+f[now][uh]);continue;}
        for(int x=1;x<=26;x++)
        {
            int p=now;
            while(p!=0&&tr[p].w[x]==0)p=tr[p].fail;
            bool bk=true;
            int pp=tr[p].w[x];
            while(pp!=0)
            { 
                if(tr[pp].ed==true){bk=false;break;}
                pp=tr[pp].fail; 
            } 
            if(bk==true)
            {
                if(tr[p].w[x]!=0)p=tr[p].w[x];
                f[p][uh+1]=MOD(f[p][uh+1]+f[now][uh]);
                if(v[p][uh+1]==false)
                {
                    v[p][uh+1]=true;
                    list[tail].now=p;list[tail].uh=uh+1;
                    tail++; 
                } 
            }
        }
    }
    int sum=1;
    for(int i=1;i<=m;i++)sum=MOD(sum*26);
    printf("%d\n",MOD(sum-ans));
    return 0;
}

 

posted @ 2018-04-24 14:47  AKCqhzdy  阅读(165)  评论(0编辑  收藏  举报