题目:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2463
题意:给出一些字符和格子对应的选择概率,随机选择L次后将得到一个长度为L的随机字符串S(每次独立随机)。给出K个模版串,计算S不包含任何模版串的概率(即任何一个模版串都不是S的连续子串)。
分析:构造出ac自动机后,每随机生成一个字符,相当于在ac自动机(改造之后的ac自动机)里面随机走一步。首先所有的单词结点(单词最后一个字符的位置)是不能走的,然后,假如这个点不是单词的结点,但是,其fail指针指向的位置是一个单词结点,那么这个点也是不能走的。把所有的不能走的点标记出来,由于由于ac机的节点(普通的节点)很少,可以记忆化搜索,dp[i][j]代表到达i位置还剩j个字符没选的概率。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 20*20+6;
const int kd = 26*2+10;
struct trie
{
int son[maxn][kd],fail[maxn],fg[maxn];
int cnt,root;
double p[kd],dp[maxn][106];
int newnode()
{
fg[cnt]=0;
fill(son[cnt],son[cnt]+kd,-1);
return cnt++;
}
void Init()
{
cnt=0;
root=newnode();
fill(p,p+kd,0);
for(int i=0;i<maxn;i++)
fill(dp[i],dp[i]+106,-1.0);
}
int idx(char ch)
{
if('0'<=ch && ch<='9') return ch-'0';
if('A'<=ch && ch<='Z') return ch-'0'-7;
return ch-'0'-13 ;
}
void Insert(char str[])
{
int i,now=root,index;
for(i=0;str[i];i++)
{
index=idx(str[i]);
if(son[now][index]==-1)
son[now][index]=newnode();
now=son[now][index];
}
fg[now]=1;
}
void findfail()
{
queue <int > q;
int i,index,now,temp;
fail[root]=root;
for(i=0;i<kd;i++)
if(son[root][i]==-1)
son[root][i]=root;
else
{
fail[son[root][i]]=root;
q.push(son[root][i]);
}
while(!q.empty())
{
temp=q.front();
q.pop();
for(i=0;i<kd;i++)
{
if(son[temp][i]==-1)
son[temp][i]=son[fail[temp]][i];
else
{
fail[son[temp][i]]=son[fail[temp]][i];
q.push(son[temp][i]);
}
fg[son[temp][i]]|=fg[son[fail[temp]][i]];
}
}
}
double dfs(int now,int L)
{
if(L==0)
return 1.0;
if(dp[now][L]>=0)
return dp[now][L];
double ret=0;
for(int i=0;i<kd;i++)
{
int v=son[now][i];
if(!fg[v] && p[i])
ret+=p[i]*dfs(v,L-1);
}
return dp[now][L]=ret;
}
}ac;
char s[1000];
int main()
{
int ncase,n,x;
double pro;
scanf("%d",&ncase);
for(int T=1;T<=ncase;T++)
{
ac.Init();
scanf("%d",&n);
while(n--)
{
scanf("%s",s);
ac.Insert(s);
}
ac.findfail();
scanf("%d",&n);
while(n--)
{
scanf("%s%lf",s,&pro);
int index=ac.idx(s[0]);
ac.p[index]=pro;
}
scanf("%d",&n);
printf("Case #%d: %.6lf\n",T,ac.dfs(ac.root,n));
}
return 0;
}