LOJ10063(BZOJ1030)(Luogu4052)【JSOI 2007】

版权声明:发现蒟蒻ff_666,但转载请注明 https://blog.csdn.net/qq_42403731/article/details/82051771

LOJ10063

这题,不就是给你N个单词,在 26 N 个文章里查嘛
然后肯定建好AC自动机后,考虑计数DP
正难则反,我们定义这样的DP:
F[k][x]表示走了k步,走到Trie上的第x个节点,且严格组成“火星文”的方案数
——那么显然,当儿子可走时累计答案: F [ k + 1 ] [ s o n ] + = F [ k ] [ x ]
最后答案就为 26 N ( i = 0 s i z e ( T r i e ) F [ m ] [ i ] )
复杂度: O ( m 26 | S | )

#include<bits/stdc++.h>
#define gt() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
#define Son c[rot][ch]
#define down AC.c[x][i]
#define fal AC.nxt[x]
using namespace std;
static char buf[1000000],*p1=buf,*p2=buf;
const int maxs=(6e3)+5,maxm=105,TT=(1e4)+7,TTT=(5e7)+7;
int n,m,que[maxs],f[maxm][maxs];
struct Trie{
    int tot,c[maxs][30],nxt[maxs];bool End[maxs];
    void insert(){
        int rot=0;char ch=gt();while(!isupper(ch)) ch=gt();
        while(isupper(ch)) ch-='A',rot=(Son?Son:Son=++tot),ch=gt();
        End[rot]=1;
    }
}AC;
void getnxt(){
    int hed=0,tal=0,x;
    for(int i=0;i<26;i++) if(AC.c[0][i]) que[++tal]=AC.c[0][i];
    while(hed!=tal){
        x=que[++hed];
        for(int i=0;i<26;i++)
          if(down) AC.nxt[que[++tal]=down]=AC.c[fal][i],AC.End[down]|=AC.End[AC.c[fal][i]];
            else down=AC.c[fal][i];
    }
}
void solve(){
    f[0][0]=1;
    for(int k=0;k<m;k++)
      for(int x=0;x<=AC.tot;x++)
        for(int i=0;i<26;i++) if(!AC.End[down]&&(f[k+1][down]+=f[k][x])>=TTT) f[k+1][down]%=TT;
    int res=1;
    for(int i=1;i<=m;i++) if((res*=26)>=TTT) res%=TT;res%=TT;
    for(int i=0;i<=AC.tot;i++) res-=f[m][i]%TT;
    printf("%d\n",(res%TT+TT)%TT);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) AC.insert();
    getnxt();
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42403731/article/details/82051771