[AC自动机+dp] whu oj 1572 I - Cyy and Fzz

题意:

给你n个串,求长度为l的串包含n个串个数的期望。

思路:

自动机dp[i][j][k] 长度为i在节点j状态为k的概率。

然后遍历一遍求期望。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
#include"map"
#include"stack"
#define N 123
#define eps 1e-8
using namespace std;
double dp[20][N][277];
int n,len;
struct Trie
{
    int next[N][27],fail[N],mark[N];
    int root,L;
    int newnode()
    {
        memset(next[L],-1,sizeof(next[L]));
        mark[L]=0;
        fail[L++]=-1;
        return L-1;
    }
    void go()
    {
        L=0;
        root=newnode();
    }
    void init(char *v,int id)
    {
        int p=root;
        for(int i=0; v[i]; i++)
        {
            int tep=v[i]-'a';
            if(next[p][tep]==-1) next[p][tep]=newnode();
            p=next[p][tep];
        }
        mark[p]|=(1<<id);
    }
    void build()
    {
        queue<int>q;
        q.push(root);
        while(!q.empty())
        {
            int p=q.front();
            q.pop();
            for(int i=0; i<26; i++)
            {
                if(next[p][i]==-1)
                {
                    if(p==root) next[p][i]=root;
                    else next[p][i]=next[fail[p]][i];
                }
                else
                {
                    if(p==root) fail[next[p][i]]=root;
                    else fail[next[p][i]]=next[fail[p]][i];
                    q.push(next[p][i]);
                    if(p!=root) mark[next[p][i]]|=mark[next[fail[p]][i]];
                }
            }
        }
    }
    void solve()
    {
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1.0;
        for(int i=1; i<=len; i++)
        {
            for(int j=0; j<L; j++)
            {
                for(int k=0; k<(1<<n); k++)
                {
                    for(int o=0; o<26; o++)
                    {
                        int tep=next[j][o];
                        dp[i][tep][mark[tep]|k]+=1.0/26*dp[i-1][j][k];
                    }
                }
            }
        }
        double ans=0;
        for(int i=0; i<L; i++)
        {
            for(int j=1; j<(1<<n); j++)
            {
                int cnt=0;
                for(int k=0; k<n; k++) if(j&(1<<k)) cnt++;
                ans+=cnt*dp[len][i][j];
            }
        }
        printf("%.6f\n",ans);
    }
} ac;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        scanf("%d%d",&n,&len);
        ac.go();
        for(int i=0; i<n; i++)
        {
            char x[123];
            scanf("%s",x);
            ac.init(x,i);
        }
        ac.build();
        ac.solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值