Time Limit: 10000MS | Memory Limit: Unknown | 64bit IO Format: %lld & %llu |
Description
H | Substring Input: Standard Input Output: Standard Output |
Given a set of pattern strings, anda text, you have to find, if any of the pattern is a substring of the text. Ifany of the pattern string can be found in text, then print “yes”, otherwise“no” (without quotes).
But, unfortunately, that’s notwhat is asked here. J
The problem described above,requires a input file generator. The generator generates a text of lengthL, by choosing L characters randomly. Probability of choosing each character isgiven 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 integer T, the number of test cases. Each casestarts with an integerK, the numberof pattern strings. Next K lines eachcontain a pattern string, followed by an integerN, number of valid characters. Next N lines each contain acharacter and the probability of selecting that character,pi. Next an integer L,the length of the string generated. The generated text can consist of only thevalid characters, given above.
There will be a blank line aftereach test case.
Output
For each test case, output the number of test case, and theprobability 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
SampleInput Outputfor 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
题意:
给出一些字符和各自出现的概率,随机选择L次得到一长为L的字符串S,给k个模板串,计算S不包含任何一个模板串的概率。
AC自动机+dp
先用所给模板串构造出AC自动机
AC自动机其实是在Trie树上面加了Fail数组,在构造自动机的时候顺便标记出哪些节点是不能经过的(单词结尾,单词为当前节点后缀的也就是Last[u]如果是不能经过的,那么当前节点u也不能经过)。
然后DP[i][j]表示走到i节点还需要走j条边而不包含模板串(不经过被标记的节点)的概率
DP[i][j] = ∑DP[k][j-1] k为可以走到的没有被标记的节点
输入的概率要初始化!
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif
#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)
const int INF = 0x3f3f3f3f;
const double eps = 10e-9;
const double PI = (4.0*atan(1.0));
const int MAX_NODE = 500 + 20;
const int SIGMA_SIZE = 62;
struct ACAutomata {
int ch[MAX_NODE][SIGMA_SIZE];
bool isWord[MAX_NODE];
int sz;
int f[MAX_NODE];
void init() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
memset(isWord, 0, sizeof(isWord));
}
int idx(char c) {
if('0' <= c && c <= '9') return c - '0';
if('A' <= c && c <= 'Z') return c - 'A' + 10;
if('a' <= c && c <= 'z') return c - 'a' + 36;
}
void insert(char * s) {
int n = strlen(s);
int u = 0;
for(int i=0; i<n; i++) {
int c = idx(s[i]);
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
isWord[sz] = false;
ch[u][c] = sz++;
}
u = ch[u][c];
}
isWord[u] = true;
}
void build() {
queue<int> Q;
f[0] = 0;
for(int i=0; i<SIGMA_SIZE; i++) {
int u = ch[0][i];
if(u) { Q.push(u); f[u] = 0; }
}
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[f[r]][c];
continue;
}
Q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
isWord[u] |= isWord[f[u]];
}
}
}
};
char s[100];
ACAutomata ac;
int vis[MAX_NODE][120];
double dp[MAX_NODE][120];
double p[SIGMA_SIZE];
double getProb(int u, int L) {
if(!L) return 1.0;
if(vis[u][L]) return dp[u][L];
vis[u][L] = 1;
double & res = dp[u][L];
res = 0.0;
for(int c=0; c<SIGMA_SIZE; c++) {
if(!ac.isWord[ac.ch[u][c]]) res += p[c] * getProb(ac.ch[u][c], L-1);
}
return res;
}
int main() {
int T;
scanf("%d", &T);
for(int kase=1; kase<=T; kase++) {
int k;
ac.init();
scanf("%d", &k);
for(int i=0; i<k; i++) {
scanf("%s", s);
ac.insert(s);
}
ac.build();
int m;
scanf("%d", &m);
// p一定要初始化!
for(int i=0; i<SIGMA_SIZE; i++) p[i] = 0;
for(int i=0; i<m; i++) {
double tp;
scanf("%s%lf", s, &tp);
p[ac.idx(s[0])] = tp;
}
int L;
scanf("%d", &L);
memset(vis, 0, sizeof(vis));
double ans = getProb(0, L);
printf("Case #%d: %.6lf\n", kase, ans);
}
return 0;
}