UVA 11468 Substring (记忆化搜索 + AC自动鸡)
Posted willems
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA 11468 Substring (记忆化搜索 + AC自动鸡)相关的知识,希望对你有一定的参考价值。
题意: 给你K个模式串, 然后,再给你 n 个字符, 和它们出现的概率 p[ i ], 模式串肯定由给定的字符组成。
且所有字符,要么是数字,要么是大小写字母。 问你生成一个长度为L的串,不包含任何模式串的概率是多少。
解: 记忆化搜索 + AC自动机。 对模式串建一个AC自动机, 不需要last[ ] 和 val[ ], 只需要一个 metch[ ]。
维护一下这个点是否是某个模式串的最后一个字符节点,若是,则这个点不能走。
然后, 剩下的就是从根节点,随便走 L 步, 记得要记忆化, 否则超时。
记得数组开足够大, 否则 wa 一下午。
#include <bits/stdc++.h> #define LL long long #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define INF 0x3f3f3f3f #define inf 0x3f3f3f3f3f3f3f3f #define mem(i, j) memset(i, j, sizeof(i)) #define pb push_back using namespace std; const int N = 20 * 20 + 5, M = 105; char op[2]; double tmp; struct Trie { int a[N][M], tot, metch[N], Fail[N], vis[N][M], n; double p[N], dp[N][M]; char ch[M]; void init() { mem(a[0], 0); tot = 1; metch[0] = 0; mem(dp, 0); mem(p, 0); mem(vis, 0); } int get(char Q) { if(Q >= ‘0‘ && Q <= ‘9‘) return Q - ‘0‘ + 1; if(Q >= ‘A‘ && Q <= ‘Z‘) return Q - ‘A‘ + 11; return Q - ‘a‘ + 37; } void join(char s[]) { int now = 0; int len = strlen(s); rep(i, 0, len - 1) { int id = get(s[i]); if(!a[now][id]) { mem(a[tot], 0); metch[tot] = 0; a[now][id] = tot++; } now = a[now][id]; } metch[now] = 1; } void getFail() { queue<int> Q; while(!Q.empty()) Q.pop(); rep(i, 1, M - 1) { if(a[0][i]) { Q.push(a[0][i]); Fail[a[0][i]] = 0; } } while(!Q.empty()) { int now = Q.front(); Q.pop(); rep(i, 1, M - 1) { int u = a[now][i]; if(u == 0) a[now][i] = a[Fail[now]][i]; else { Q.push(u); Fail[u] = a[Fail[now]][i]; metch[u] |= metch[Fail[u]]; } } } } double dfs(int now, int L) { if(!L) return 1.0; if(vis[now][L]) return dp[now][L]; vis[now][L] = 1; double &ans = dp[now][L]; ans = 0.0; rep(i, 1, M - 1) { /// 枚举所有可能字符 if(!metch[a[now][i]]) { /// 这个节点可以走 ans += p[i] * dfs(a[now][i], L - 1); } } return ans; } void scan() { scanf("%d", &n); rep(i, 1, n) { scanf("%s %lf", op, &tmp); int id = get(op[0]); p[id] = tmp; } } void print(int cas) { int L; scanf("%d", &L); printf("Case #%d: ", cas); printf("%.6f ", dfs(0, L)); } }; Trie AC; char b[25]; int main() { int _; scanf("%d", &_); int cas = 0; while(_--) { AC.init(); int k; scanf("%d", &k); rep(i, 1, k) { scanf("%s", b); AC.join(b); } AC.getFail(); AC.scan(); AC.print(++cas); } return 0; }
以上是关于UVA 11468 Substring (记忆化搜索 + AC自动鸡)的主要内容,如果未能解决你的问题,请参考以下文章
UVa 11468 Substring (AC自动机+概率DP)