AC自动机+记忆话搜索
H | Substring Input:Standard Input Output:Standard Output | |
Given a set of pattern strings, and a text, you have to find, if any of the pattern is a substring of the text. If any of the pattern string can be found in text, then print “yes”, otherwise “no” (without quotes).
But, unfortunately, that’s not what is asked here.J
The problem described above, requires a input file generator. The generator generates a text of lengthL, by choosingLcharacters randomly. Probability of choosing each character is given as priori, and independent of choosing others.
Now, given a set of patterns, calculate the probability of a valid program generating “no”.
Input
First line contains an integerT, the number of test cases. Each case starts with an integerK, the number of pattern strings. NextKlines each contain a pattern string, followed by an integerN, number of valid characters.NextNlines each contain a character and the probability of selecting that character,pi. Next an integerL, the length of the string generated. The generated text can consist of only the valid characters, given above.
There will be a blank line after each test case.
Output
For each test case, output the number of test case, and the probability of getting a “no”.
Constraints
·T≤ 50
·K ≤ 20
·Length of each pattern string is between 1 and 20
·Each pattern string consists of only alphanumeric characters (‘a’ to ‘z’, ‘A’ to ‘Z’,’0’ to ‘9’)
·Valid characters are all alphanumeric characters
·∑pi= 1
·L ≤ 100
Sample InputOutput for Sample Input
2 1 a 2 a 0.5 b 0.5 2
2 ab ab 2 a 0.2 b 0.8 2 | Case #1: 0.250000 Case #2: 0.840000 |
Problem Setter: Manzurur Rahman Khan
每产生一个字母,相当与在AC自动机中任意走了一步。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
using namespace std;
const int maxn=1700;
int idx(char c)
{
if(c>='0'&&c<='9')
{
return c-'0';
}
else if(c>='a'&&c<='z')
{
return c-'a'+10;
}
else if(c>='A'&&c<='Z')
{
return c-'A'+10+26;
}
}
int chd[maxn][65],match[maxn],f[maxn],sz;
bool vis[maxn][120];
void init()
{
sz=1;
memset(chd[0],0,sizeof(chd[0]));
memset(match,0,sizeof(match));
memset(f,0,sizeof(f));
}
void insert(char *p)
{
int u=0;
for(;*p;p++)
{
int t=idx(*p);
if(!chd[u][t])
{
memset(chd[sz],0,sizeof(chd[sz]));
chd[u][t]=sz++;
}
u=chd[u][t];
}
match[u]=1;
}
int getFail()
{
queue<int> q;
f[0]=0;
for(int c=0;c<62;c++)
{
int u=chd[0][c];
if(u)
{
f[u]=0;q.push(u);
}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<62;c++)
{
int u=chd[r][c];
if(!u)
{
chd[r][c]=chd[f[r]][c]; continue;
}
q.push(u);
int v=f[r];
while(v&&!chd[v][c]) v=f[v];
f[u]=chd[v][c];
match[u]|=match[f[u]];
}
}
}
int K,N,L;
double prob[100],dp[maxn][120];
double getProb(int u,int l)
{
if(l==0) return 1.;
if(vis[u][l]) return dp[u][l];
vis[u][l]=1;
double a=0.;
for(int i=0;i<62;i++)
{
if(!match[chd[u][i]])
a+=prob[i]*getProb(chd[u][i],l-1);
}
return dp[u][l]=a;
}
int main()
{
int t,cas=1;
char word[30];
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&K);
for(int i=0;i<K;i++)
{
scanf("%s",word);
insert(word);
}
getFail();
memset(prob,0,sizeof(prob));
scanf("%d",&N);
for(int i=0;i<N;i++)
{
double p;
scanf("%s%lf",word,&p);
prob[idx(word[0])]=p;
}
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
scanf("%d",&L);
printf("Case #%d: %lf\n",cas++,getProb(0,L));
}
return 0;
}