题意: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]); }