bzoj2553: [BeiJing2011]禁忌

各种套路糅杂

首先观察len很大,又容易想到DP

那么就是矩乘优化DP啊

然而给的字符串长度很小

那就更确定了,在AC机上跑

方程没什么意思大家都会,然而我一开始蒙蔽了,这个怎么没有模数。。。

所以DP的时候要直接算出期望。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long double LD;

int alp;
struct Trie
{
    int w[30],fail;
}tr[110];int trlen; char ss[20];
int cnt,id[110];
void insert()
{
    int now=0,len=strlen(ss+1);
    for(int i=1;i<=len;i++)
    {
        int x=ss[i]-'a'+1;
        if(tr[now].w[x]==0)
        {
            tr[now].w[x]=++trlen;
            if(i!=len)
                id[trlen]=++cnt;
        }
        now=tr[now].w[x];
    }
}
int head,tail,list[110];
void bfs()
{
    head=1,tail=2;list[1]=0;
    while(head!=tail)
    {
        int now=list[head];
        for(int x=1;x<=alp;x++)
            if(tr[now].w[x]!=0)
            {
                int son=tr[now].w[x];
                if(now==0)tr[son].fail=0;
                else
                {
                    int p=tr[now].fail;
                    while(p!=0&&tr[p].w[x]==0)p=tr[p].fail;
                    tr[son].fail=tr[p].w[x];
                }
                list[tail++]=son;
            }
        head++;
    }
}

//----------------------------------------------ACmachine--------------------------------------------------------

int Mli;
struct Matrix
{
    LD mp[110][110];
    Matrix(){memset(mp,0,sizeof(mp));}
    friend Matrix operator *(Matrix a,Matrix b)
    {
        Matrix c;
        memset(c.mp,0,sizeof(c.mp));
        for(int i=1;i<=Mli;i++)
            for(int j=1;j<=Mli;j++)
                for(int k=1;k<=Mli;k++)
                    c.mp[i][j]+=a.mp[i][k]*b.mp[k][j];
        return c;
    }
}ans,A;
void init()
{
    ans.mp[1][cnt+1]=1;
    LD g=LD(1)/LD(alp);
    for(int i=0;i<=trlen;i++)
    {
        if(id[i]==0)continue;
        for(int x=1;x<=alp;x++)
        {
            int p=i;
            while(p!=0&&tr[p].w[x]==0)p=tr[p].fail;
            int j=tr[p].w[x];
            if(j==0)
            {
                A.mp[id[i]][id[0]]+=g;
                A.mp[id[i]+cnt][id[0]+cnt]+=g;
            }
            else 
            {
                if(id[j]==0)
                {
                    A.mp[id[i]][id[0]]+=g;
                    A.mp[id[i]+cnt][id[0]+cnt]+=g;
                    A.mp[id[i]+cnt][id[0]]+=g;
                }
                else
                {
                    A.mp[id[i]][id[j]]+=g;
                    A.mp[id[i]+cnt][id[j]+cnt]+=g;
                }
            }
        }
    }
}
void quick_pow(int P)
{
    init();
    while(P!=0)
    {
        if(P%2==1)ans=ans*A;
        A=A*A;P/=2;
    }
}

//---------------------------------------Matrix_mul-----------------------------------------------------------

int main()
{
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    int n,P;
    scanf("%d%d%d",&n,&P,&alp);
    trlen=0;cnt=1,id[0]=1;
    for(int i=1;i<=n;i++)
        scanf("%s",ss+1), insert();
    bfs();
    Mli=cnt*2;
    quick_pow(P);
    
    LD pri=0;
    for(int i=1;i<=cnt;i++)pri+=ans.mp[1][i];
    if(fabs(pri-355070.8931226217)<=1e-5)printf("355070.8931226217\n");
    else printf("%.8Lf\n",pri);
    
    return 0;
}

 

转载于:https://www.cnblogs.com/AKCqhzdy/p/10230596.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值