LOJ10063(BZOJ1030)(Luogu4052)【JSOI 2007】

13 篇文章 0 订阅
9 篇文章 0 订阅

LOJ10063

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值