这题pro数组开小了,一直TLE。
就是简单的记忆化搜索,走不是单词节点的点就可以,记得标出危险节点。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxnode=500;
int idx[256];
int k,n,L;
struct DFA{
int ch[maxnode][64];
int f[maxnode];
int match[maxnode];
int sz;
void clear() {sz=1;memset(ch[0],0,sizeof(ch[0]));}
void insert(char *s)
{
int u=0;
for(int i=0;s[i];i++)
{
int c=idx[s[i]];
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
match[sz]=0;
ch[u][c]=sz++;
}
u=ch[u][c];
}
match[u]=1;
}
void getfail()
{
queue<int> q;
f[0]=0;
for(int i=0;i<64;i++) {
int v=ch[0][i];
if(v) {f[v]=0;q.push(v);}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<64;c++)
{
int u=ch[r][c];
if(!u) {ch[r][c]=ch[f[r]][c];continue;}
q.push(u);int v=f[r];
while(v&&!ch[v][c]) v=f[v];
f[u]=ch[v][c];
match[u]|=match[f[u]];
}
}
}
};
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define ss(x) scanf("%d",&x)
DFA ac;
char s[30][30];
double pro[64];
int vis[maxnode][105];
double d[maxnode][105];
double getPro(int u,int l)
{
if(!l) return 1.0;
if(vis[u][l]) return d[u][l];
vis[u][l]=1;
double &ans=d[u][l];
ans=0.0;
rep(i,0,n) if(!ac.match[ac.ch[u][i]]) ans+=pro[i]*getPro(ac.ch[u][i],l-1);
return ans;
}
int main()
{
int t,kase=0;ss(t);
while(t--)
{
ss(k);rep(i,0,k) scanf("%s",s[i]);
ss(n);rep(i,0,n) {char cmd[10];scanf("%s%lf",cmd,&pro[i]);idx[cmd[0]]=i;}
ac.clear();
rep(i,0,k) ac.insert(s[i]);
ac.getfail();
ss(L);
memset(vis,0,sizeof(vis));
printf("Case #%d: %.6lf\n",++kase,getPro(0,L));
}
return 0;
}