题目大意:给一些模板串,一些字符的出现概率。问不会出现模板串的概率是多少。
题目分析:是比较简单的概率DP+AC自动机。利用全概率公式递推即可。
代码如下:
# include<iostream>
# include<cstdio>
# include<queue>
# include<cstring>
# include<algorithm>
using namespace std;
const int N=1000;
int ch[N+5][65];
int cnt;
bool match[N+5];
int f[N+5];
char str[65][5];
double pi[65];
double dp[N+5][105];
bool vis[N+5][105];
void init()
{
cnt=0;
memset(pi,0,sizeof(pi));
memset(ch,0,sizeof(ch));
memset(match,false,sizeof(match));
}
int idx(char c)
{
if(c>='0'&&c<='9') return c-'0';
if(c>='a'&&c<='z') return c-'a'+10;
return c-'A'+36;
}
void insert(string s)
{
int n=s.size();
int root=0;
for(int i=0;i<n;++i){
int c=idx(s[i]);
if(!ch[root][c]) ch[root][c]=++cnt;
root=ch[root][c];
}
match[root]=true;
}
void getFail()
{
queue<int>q;
f[0]=0;
for(int i=0;i<62;++i){
int u=ch[0][i];
if(!u) continue;
f[u]=0;
q.push(u);
}
while(!q.empty())
{
int root=q.front();
q.pop();
for(int i=0;i<62;++i){
int u=ch[root][i];
if(!u){
ch[root][i]=ch[f[root]][i];
continue;
}
q.push(u);
int v=f[root];
while(v&&!ch[v][i]) v=f[v];
f[u]=ch[v][i];
match[u]|=match[f[u]];
}
}
}
double dfs(int u,int L)
{
if(vis[u][L]) return dp[u][L];
vis[u][L]=true;
if(L==0) return dp[u][L]=1.0;
double &ans=dp[u][L];
ans=0.0;
for(int i=0;i<62;++i) if(!match[ch[u][i]])
ans+=pi[i]*dfs(ch[u][i],L-1);
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
int T,n,m,L,cas=0;
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
string p;
for(int i=0;i<n;++i){
cin>>p;
insert(p);
}
getFail();
scanf("%d",&m);
double pp;
for(int i=0;i<m;++i){
scanf("%s%lf",str[i],&pp);
pi[idx(str[i][0])]=pp;
}
scanf("%d",&L);
memset(vis,false,sizeof(vis));
printf("Case #%d: %.6lf\n",++cas,dfs(0,L));
}
return 0;
}