• [BZOJ1030][JSOI2007]文本生成器(AC自动机+DP)


    [不稳定的传送门]

    Solution

    考虑算出所有不包含给定字符串的方案数,在用总数减去就行了

    f[i][j]表示到第i个字符串,当前停在自动机上j点的方案数

    Code

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define N 6010
    using namespace std;
    
    char s[110];
    const int mo=10007;
    int n,m,f[110][N],T[N][27],fail[N],tot=1,mark[N],q[N],sum=1,Ans;
    
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    void Insert(){
    	scanf("%s
    ",&s);
    	int len=strlen(s),now=1;
    	for(int i=0;i<len;++i){
    		if(!T[now][s[i]-64]) T[now][s[i]-64]=++tot;
    		now=T[now][s[i]-64];
    	}
    	mark[now]=1;
    }
    
    void getfail(){
    	for(int i=1;i<=26;++i) T[0][i]=1;
    	int k,now,h=0,t=0;q[++t]=1;
    	while(h<t){
    		mark[now=q[++h]]|=mark[fail[now]];
    		for(int i=1;i<=26;++i)
    			if(T[now][i]){
    				k=fail[now];
    				while(!T[k][i]) k=fail[k];
    				fail[q[++t]=T[now][i]]=T[k][i];
    			}
    	}
    }
    
    int main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;++i) Insert();
    	getfail();
    	f[0][1]=1;
    	for(int i=0;i<m;++i)
    		for(int j=1;j<=tot;++j)
    			for(int k=1;k<=26;++k)
    				if(!mark[j]){
    					int now=j;
    					while(!T[now][k]) now=fail[now];
    					now=T[now][k];
    					(f[i+1][now]+=f[i][j])%=mo;
    				}
    	for(int i=1;i<=m;++i) sum=sum*26%mo;
    	for(int i=0;i<=tot;++i) if(!mark[i]) Ans=(Ans+f[m][i])%mo;
    	printf("%d
    ",(sum-Ans+mo)%mo);
    	return 0;
    }
    
  • 相关阅读:
    最大流最小割——bzoj1001狼抓兔子,洛谷P2598
    求最小公因数和最大公倍数
    归并排序
    Splay
    Tarjan判断为什么不能把dfn写成low
    2-SAT问题
    离散数学-传递闭包(POJ3275)
    POJ3190
    安装环境gcc;
    二分折半排序
  • 原文地址:https://www.cnblogs.com/void-f/p/8921708.html
Copyright © 2020-2023  润新知