您的位置:首页 > 其它

bzoj2553【beijing2011】禁忌

2017-02-28 19:51 483 查看
题意: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]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: