zoukankan      html  css  js  c++  java
  • [bzoj] 1030 文本生成器 || AC自动机+dp

    原题

    给出n个字符串,求随机生成一个m长度的字符串,有多少个是可辨识的(即出现了n个字符串中的任意字符串)


    正难则反
    求有多少个不可辨识的,26^m-不可辨识即为答案
    f[i][j]表示填到第i个字符,在自动机上第j个节点时的答案
    状态转移方程很明显:
    f[i][j]+=f[i-1][f[j]]

    #include<cstdio>
    #include<cstring>
    #define p 10007
    #define N 6010
    using namespace std;
    int n,m,sze=1,ans1,ans2=1,a[N][27],fail[N],q[N],f[110][N];
    char s[110];
    bool is[N];
    
    void ins()
    {
        int now=1,c,l=strlen(s);
        for (int i=0;i<l;i++)
        {
    	c=s[i]-'A'+1;
    	if (a[now][c]) now=a[now][c];
    	else now=a[now][c]=++sze;
        }
        is[now]=1;
    }
    
    void acmatch()
    {
        int l=0,r=1,now;
        q[0]=1;fail[1]=0;
        while (l<r)
        {
    	now=q[l++];
    	for (int i=1;i<=26;i++)
    	{
    	    if (!a[now][i]) continue;//如果没有这条边
    	    int k=fail[now];
    	    while (!a[k][i]) k=fail[k];//找到第一个有该边的该节点的后缀节点
    	    fail[a[now][i]]=a[k][i];//我儿子的后缀节点等于我的后缀节点的该边
    	    if (is[a[k][i]])//传递结尾标记
    		is[a[now][i]]=1;
    	    q[r++]=a[now][i];
    	}
        }
    }
    
    void dp(int x)
    {
        for(int i=1;i<=sze;i++)
        {
    	if (is[i] || !f[x-1][i]) continue;//如果这个节点是结尾(不能出现结尾)或者到前一位就已经不能在这个节点了
    	for (int j=1;j<=26;j++)//枚举下一位
    	{
    	    int k=i;
    	    while (!a[k][j]) k=fail[k];//找到后缀节点
    	    f[x][a[k][j]]=(f[x][a[k][j]]+f[x-1][i])%p;//更新答案
    	}
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=26;i++) a[0][i]=1;
        for (int i=1;i<=n;i++)
        {
    	scanf("%s",s);
    	ins();
        }
        acmatch();
        f[0][1]=1;
        for (int i=1;i<=m;i++) dp(i);//f[i][j]表示考虑到第x位在AC自动机上第j个节点的答案
        for (int i=1;i<=m;i++)
    	ans2=ans2*26%p;//26^m为总字符串数
        for (int i=1;i<=sze;i++)
    	if (!is[i]) ans1=(ans1+f[m][i])%p;//ans2为不能认出来的字符串数
        printf("%d",(ans2-ans1+p)%p);
        return 0;
    }
    
  • 相关阅读:
    最短路+线段交 POJ 1556 好题
    判断线段和直线相交 POJ 3304
    nginx配置pathinfo模式,解决访问404
    使用ORM关联关系,如何自己关联自己
    PHPCMS
    linux安装redis服务,配置PHP扩展
    后台银行卡算法
    静态类和非静态类
    PHP的闭包和匿名函数
    php获取前一天时间段,每个月的第一天到最后一天
  • 原文地址:https://www.cnblogs.com/mrha/p/8241824.html
Copyright © 2011-2022 走看看