bzoj2553【beijing2011】禁忌

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=2553

sol  :puts("nan"); (逃~

   ac自动机+矩阵快速幂

   先将所有的串放到ac自动机上,贪心匹配,对一个包含禁忌串的节点划分出一段

   设f[i][j]表示走了i步到达AC自动机上的j节点的概率

   转移方程为f[i+1][k]=f[i][j]/alphabet

   由于i较大,但是每一步的转移是一样的,所以可以用矩阵快速幂优化

   P.S.喜sang闻xin乐bing见kuang的出题人卡精度QAQ,需要开long double

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=110;
struct Node { int l,r; long double f[Mx][Mx]; } str,final;  
int n,m,cnt,len,num,ch[Mx][26],fail[Mx],q[Mx],jud[Mx];  
char s[Mx]; 
void build_trie()
{  
    int x=0;  
    for(int i=1;i<=m;i++)
    {  
        if(!ch[x][s[i]-'a']) ch[x][s[i]-'a']=++cnt;
        x=ch[x][s[i]-'a'];
        if(jud[x]) break;
    }  
    jud[x]=1; 
}  
void get_fail()
{  
    int h=0,t=1;q[h]=0;  
    while(h!=t)
    {  
        int now=q[h++]; if(h>Mx) h=0; 
        for(int i=0;i<num;i++)
            if(ch[now][i])
            {  
                int x=ch[now][i],y=fail[now];
                while(y&&(!ch[y][i])) y=fail[y]; 
                if(ch[y][i]!=x) fail[x]=ch[y][i];
                else fail[x]=0;
                q[t++]=x; if(t>Mx) t=0;
            }
            else ch[now][i]=ch[fail[now]][i];  
    }  
    str.f[cnt+1][cnt+1]=1;
}
Node mul(Node x,Node y)
{  
    Node tmp;tmp.l=x.l;tmp.r=y.r;
    memset(tmp.f,0,sizeof(tmp.f));
    for(int k=0;k<x.r;k++)  
        for(int i=0;i<x.l;i++)  
            for(int j=0;j<y.r;j++)  
                tmp.f[i][j]+=x.f[i][k]*y.f[k][j];  
    return tmp; 
}  
void build()
{
    get_fail();
    long double tmp=(long double) 1/num;  
    for(int i=0;i<=cnt;i++) 
        if(!jud[i])  
            for(int j=0;j<num;j++)
                if(jud[ch[i][j]]) str.f[i][cnt+1]+=tmp,str.f[i][0]+=tmp;  
                else str.f[i][ch[i][j]]+=tmp;  
    str.f[cnt+1][cnt+1]=1;
}  
void dfs(int x)
{  
    if(jud[x])
        for(int i=0;i<num;i++) ch[x][i]=0;  
    else
        for(int i=0;i<num;i++)
            if(ch[x][i]) dfs(ch[x][i]);  
}
void pre()
{
    scanf("%d%d%d",&n,&len,&num);  
    for (int i=1;i<=n;i++)
    {  
        scanf("%s",s+1); m=strlen(s+1);  
        build_trie();  
    }   
    dfs(0);
    str.l=str.r=cnt+2;  
    final.l=1,final.r=cnt+2,final.f[0][0]=1;
}
int main()
{  
    pre();
    build();  
    for( ;len;len>>=1,str=mul(str,str)) if(len&1) final=mul(final,str);  
    printf("%.9lf",(double) final.f[0][cnt+1]);  
}

 

posted @ 2017-02-28 19:51  Czarina  阅读(142)  评论(0编辑  收藏  举报