传送门

题意: 给你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 ;
}

最新文章

  1. [Android Tips] 24. Gradle listing project dependencies
  2. [ZigBee] 4、ZigBee基础实验——中断
  3. 《BI项目笔记》报到信息分析Cube
  4. 注册asp.net
  5. Oracle 学习系列之二(会话与事务级临时表和dual表 )
  6. acdream 1044
  7. 剑指offer-面试题18.树的子结构
  8. 【ActiveMQ】设置自动重连
  9. 关于oracle12c对RAW裸设备的支持?
  10. hdu_2608_0 or 1_数论
  11. CodeForces 660D Number of Parallelograms
  12. 性能测试分享:Jmeter的api监控工具解决方案
  13. 使用 SLF4J + LogBack 构建日志系统(转)
  14. JavaSE基础篇—数据类型和运算符
  15. hive字段名、注释中文显示问号
  16. jQuery代码优化的9种方法
  17. Postgres使用ALTER USER命令修改用户的密码、密码过期,锁定,解锁
  18. Centos7安装jdk1.8并查找jdk安装目录
  19. 词袋模型(BOW, bag of words)
  20. 和为k的最长子数组及其延伸

热门文章

  1. flink linux安装 单机版
  2. nginx.conf指令详解
  3. Jmeter参数化(_csvread函数、CSV Data Set Config)
  4. golang ---网卡信息
  5. WCF NetTcpBinding
  6. azkban从编译开始安装
  7. JS基础_强制类型转换-Number
  8. OO第四单元(UML)单元总结
  9. typescript_类
  10. SetCurrentCellAddressCore 函数的可重入调用