dp[i][l]表示在结点i再走l步不碰到单词结点的概率。
关键一步:val[u]|=val[fail[u]];
#include<iostream> #include<vector> #include<queue> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<algorithm> using namespace std; const int MAX_NODE=444; const int SIGMA_SIZE=62; struct ACAutomation { int sz; int fail[MAX_NODE]; int ch[MAX_NODE][SIGMA_SIZE]; int val[MAX_NODE]; double dp[444][200]; int idx(char c) { if(c>='0'&&c<='9')return c-'0'; if(c>='A'&&c<='Z')return c-'A'+10; if(c>='a'&&c<='z')return c-'a'+36; } void init() { sz=1; memset(ch[0],0,sizeof(ch[0])); val[0]=0; memset(dp,-1,sizeof(dp)); } void insert(const char *s) { int u=0; for(int i=0; s[i]!='\0'; i++) { int v=idx(s[i]); if(!ch[u][v]) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][v]=sz++; } u=ch[u][v]; } val[u]=1; } void construct() { fail[0]=0; queue<int> q; for(int c=0; c<SIGMA_SIZE; c++) { int u=ch[0][c]; if(u) { fail[u]=0; q.push(u); } } while(!q.empty()) { int r=q.front(); q.pop(); for(int c=0; c<SIGMA_SIZE; c++) { int u=ch[r][c]; if(!u) { ch[r][c]=ch[fail[r]][c]; continue; } q.push(u); int v=fail[r]; while(v&&!ch[v][c])v=fail[v]; fail[u]=ch[v][c]; val[u]|=val[fail[u]]; } } } double f(int u,int l,double *da) { if(!l)return 1.0; if(dp[u][l]>=0)return dp[u][l]; double &x=dp[u][l]; x=0; for(int c=0;c<SIGMA_SIZE;c++)if(!val[ch[u][c]]) x+=da[c]*f(ch[u][c],l-1,da); return x; } }ac; double da[66]; int main() { // freopen("d:\\in.txt","r",stdin); int t; scanf("%d",&t); for(int ca=1;ca<=t;ca++) { ac.init(); int n; scanf("%d",&n); for(int i=1;i<=n;i++) { char s[100]; scanf("%s",s); ac.insert(s); } ac.construct(); memset(da,0,sizeof(da)); scanf("%d",&n); for(int i=1;i<=n;i++) { char ch[10]; double p; scanf("%s%lf",ch,&p); da[ac.idx(ch[0])]=p; } int l; scanf("%d",&l); printf("Case #%d: %lf\n",ca,ac.f(0,l,da)); } return 0; }