UVA 11468 Substring (记忆化搜索 + AC自动鸡)
2024-09-22 22:38:48
题意: 给你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 = * + , M = ;
char op[];
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[], ); tot = ; metch[] = ; mem(dp, ); mem(p, ); mem(vis, );
}
int get(char Q) {
if(Q >= '' && Q <= '') return Q - '' + ;
if(Q >= 'A' && Q <= 'Z') return Q - 'A' + ;
return Q - 'a' + ;
}
void join(char s[]) {
int now = ; int len = strlen(s);
rep(i, , len - ) {
int id = get(s[i]);
if(!a[now][id]) {
mem(a[tot], ); metch[tot] = ;
a[now][id] = tot++;
}
now = a[now][id];
}
metch[now] = ;
}
void getFail() {
queue<int> Q; while(!Q.empty()) Q.pop();
rep(i, , M - ) {
if(a[][i]) {
Q.push(a[][i]); Fail[a[][i]] = ;
}
}
while(!Q.empty()) {
int now = Q.front(); Q.pop();
rep(i, , M - ) {
int u = a[now][i];
if(u == ) 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] = ;
double &ans = dp[now][L];
ans = 0.0;
rep(i, , M - ) { /// 枚举所有可能字符
if(!metch[a[now][i]]) { /// 这个节点可以走
ans += p[i] * dfs(a[now][i], L - );
}
}
return ans;
}
void scan() {
scanf("%d", &n);
rep(i, , n) {
scanf("%s %lf", op, &tmp);
int id = get(op[]);
p[id] = tmp;
}
}
void print(int cas) {
int L; scanf("%d", &L);
printf("Case #%d: ", cas);
printf("%.6f\n", dfs(, L));
}
};
Trie AC;
char b[];
int main() {
int _; scanf("%d", &_); int cas = ;
while(_--) {
AC.init();
int k; scanf("%d", &k);
rep(i, , k) {
scanf("%s", b); AC.join(b);
}
AC.getFail();
AC.scan();
AC.print(++cas);
}
return ;
}
最新文章
- [Android Tips] 24. Gradle listing project dependencies
- [ZigBee] 4、ZigBee基础实验——中断
- 《BI项目笔记》报到信息分析Cube
- 注册asp.net
- Oracle 学习系列之二(会话与事务级临时表和dual表 )
- acdream 1044
- 剑指offer-面试题18.树的子结构
- 【ActiveMQ】设置自动重连
- 关于oracle12c对RAW裸设备的支持?
- hdu_2608_0 or 1_数论
- CodeForces 660D Number of Parallelograms
- 性能测试分享:Jmeter的api监控工具解决方案
- 使用 SLF4J + LogBack 构建日志系统(转)
- JavaSE基础篇—数据类型和运算符
- hive字段名、注释中文显示问号
- jQuery代码优化的9种方法
- Postgres使用ALTER USER命令修改用户的密码、密码过期,锁定,解锁
- Centos7安装jdk1.8并查找jdk安装目录
- 词袋模型(BOW, bag of words)
- 和为k的最长子数组及其延伸