题意:
给出一些字符和各自对应的选择概率,随机选择L次后将得到一个长度为L的随机字符串S(每次独立随机)。
给出K个模板串,计算S不包含任何一个模板串的概率(即任何一个模板串都不是S的连续子串)。
思路:
多模式匹配,显然的Ac自动机, 每个字符都有一个概率, 就是很显然的自动机 + dp了
令dp[i][j] 表示构造字符串的第i 位, 在自动机节点j 不包含病毒串的概率。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
using namespace std;
int get(char ch){
if (ch >= 'a' && ch <= 'z'){
return ch - 'a';
}
if (ch >= 'A' && ch <= 'Z'){
return ch - 'A' + 26;
}
if (ch >= '0' && ch <= '9'){
return ch - '0' + 52;
}
}
const int maxn = 500;
const int maxm = 62;
char cmd[50];
double mp[128];
struct Trie{
int L, root;
int next[maxn][maxm];
int fail[maxn];
int flag[maxn];
double dp[101][maxn];
void init(){
L = 0;
root = newnode();
}
void insert(char* s){
int len = strlen(s);
int nod = root;
for (int i = 0; i < len; ++i){
int id = get(s[i]);
if (next[nod][id] == -1){
next[nod][id] = newnode();
}
nod = next[nod][id];
}
flag[nod] = 1;
}
int newnode(){
for (int i = 0; i < maxm; ++i){
next[L][i] = -1;
}
flag[L] = 0;
return L++;
}
void bfs(){
queue<int>q;
fail[root] = root;
for (int i = 0; i < maxm; ++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 u = q.front(); q.pop();
flag[u] |= flag[fail[u] ];
for (int i = 0; i < maxm; ++i){
if (next[u][i] == -1){
next[u][i] = next[fail[u] ][i];
}
else {
fail[next[u][i] ] = next[fail[u] ][i];
q.push(next[u][i]);
}
}
}
}
void solve(int n){
memset(dp,0,sizeof dp);
dp[0][0] = 1.0;
for (int i = 1; i <= n; ++i){
for (int j = 0; j < L; ++j){
if (dp[i-1][j] == 0) continue;
for (int k = 0; k < maxm; ++k){
int nx = next[j][k];
if (flag[nx]) continue;
dp[i][nx] += dp[i-1][j] * mp[k];
}
}
}
double ans = 0;
for (int i = 0; i < L; ++i){
ans += dp[n][i];
}
printf("%.6f\n", ans);
}
}ac;
int main(){
int T;
int ks = 0;
scanf("%d",&T);
while(T--){
int n;
scanf("%d", &n);
memset(mp,0,sizeof mp);
ac.init();
for (int i = 0; i < n; ++i){
scanf("%s", cmd);
ac.insert(cmd);
}
ac.bfs();
scanf("%d", &n);
for (int i = 0; i < n; ++i){
double x;
scanf("%s%lf", cmd, &x);
mp[get(cmd[0]) ] = x;
}
scanf("%d", &n);
printf("Case #%d: ", ++ks);
ac.solve(n);
}
return 0;
}