题意:
求最后构成的长度为L的字符串不含有模式串的概率,没一个字符的概率已经给出来了。
思路:
自动机构造转移,然后dp[i][j]表示现在是第i步,在j这个状态。
转移方程就很好写了。
code:
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
double m[1000];
double dp[110][5110];
int Next[5010][63],fail[5010],End[5010];
struct Trie
{
int root,L;
int idx(char x){
if(x<='z' && x>='a') return x-'a';
if(x<='Z' && x>='A') return x-'A'+26;
if(x<='9' && x>='0') return x-'0'+52;
}
int newnode()
{
for(int i = 0;i < 62;i++)
Next[L][i] = -1;
End[L++] = 0;
return L-1;
}
void init()
{
L = 0;
root = newnode();
}
void insert(char buf[])
{
int len = strlen(buf);
int now = root;
for(int i = 0;i < len;i++)
{
if(Next[now][idx(buf[i])] == -1)
Next[now][idx(buf[i])] = newnode();
now = Next[now][idx(buf[i])];
}
End[now] = 1;
}
void build()
{
queue<int>Q;
fail[root] = root;
for(int i = 0;i < 62;i++)
if(Next[root][i] == -1)
Next[root][i] = root;
else
{
fail[Next[root][i]] = root;
Q.push(Next[root][i]);
}
while( !Q.empty() )
{
int now = Q.front();
Q.pop();
End[now] |= End[fail[now]];
for(int i = 0;i < 62;i++)
if(Next[now][i] == -1)
Next[now][i] = Next[fail[now]][i];
else
{
fail[Next[now][i]]=Next[fail[now]][i];
Q.push(Next[now][i]);
}
}
}
void query(){
memset(dp, 0, sizeof(dp));
dp[0][root] = 1;
for(int i=0; i<=n; i++){
for(int j=0; j<L; j++){
for(int k=0; k<62; k++)
if(End[Next[j][k]] == 0)
dp[i+1][Next[j][k]] += dp[i][j]*m[k];
}
}
}
};
char tmp[40];
int T;
int main(){
Trie t;
cin>>T;
int icase = 0;
while(T--){
memset(m, 0, sizeof(m));
int k;
cin>>k;
t.init();
for(int i=1; i<=k; i++){
scanf("%s", tmp);
t.insert(tmp);
}
t.build();
cin>>n;
double tt;
for(int i=1; i<=n; i++){
scanf("%s %lf", tmp, &tt);
m[t.idx(tmp[0])] = tt;
}
cin>>n;
t.query();
double res = 0;
for(int i=0; i<t.L; i++)
res += dp[n][i];
printf("Case #%d: %.6f\n", ++icase, res);
}
return 0;
}