UVa 11468 (AC自动机 概率DP) Substring

将K个模板串构成一个AC自动机,那些能匹配到的单词节点都称之为禁止节点。

然后问题就变成了在Tire树上走L步且不经过禁止节点的概率。

根据全概率公式用记忆化搜索求解。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <queue>
  4 using namespace std;
  5
  6 const int maxnode = 500;
  7 const int sigma_size = 64;
  8 int idx[256];
  9
 10 struct AhoCorasickAutomata
 11 {
 12     int ch[maxnode][sigma_size];
 13     int match[maxnode];
 14     int f[maxnode];
 15     int sz;
 16
 17     void init() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }
 18
 19     void insert(char* s)
 20     {
 21         int u = 0, n = strlen(s);
 22         for(int i = 0; i < n; i++)
 23         {
 24             int c = idx[s[i]];
 25             if(!ch[u][c])
 26             {
 27                 memset(ch[sz], 0, sizeof(ch[sz]));
 28                 match[sz] = 0;
 29                 ch[u][c] = sz++;
 30             }
 31             u = ch[u][c];
 32         }
 33         match[u] = 1;
 34     }
 35
 36     void getFail()
 37     {
 38         queue<int> q;
 39         f[0] = 0;
 40         for(int c = 0; c < sigma_size; c++)
 41         {
 42             int u = ch[0][c];
 43             if(u) { f[u] = 0; q.push(u); }
 44         }
 45         while(!q.empty())
 46         {
 47             int r = q.front(); q.pop();
 48             for(int c = 0; c < sigma_size; c++)
 49             {
 50                 int u = ch[r][c];
 51                 if(!u) { ch[r][c] = ch[f[r]][c]; continue; }
 52                 q.push(u);
 53                 int v = f[r];
 54                 while(v && !ch[v][c]) v = f[v];
 55                 f[u] = ch[v][c];
 56                 match[u] |= match[f[u]];
 57             }
 58         }
 59     }
 60 }ac;
 61
 62 int n;
 63 const int maxl = 100 + 10;
 64 char s[30][30];
 65 double prob[sigma_size];
 66
 67 int vis[maxnode][maxl];
 68 double d[maxnode][maxl];
 69
 70 double getProb(int u, int L)
 71 {
 72     if(L == 0) return 1.0;
 73     if(vis[u][L]) return d[u][L];
 74     vis[u][L] = 1;
 75     double& ans = d[u][L];
 76     ans = 0;
 77     for(int c = 0; c < n; c++)
 78         if(!ac.match[ac.ch[u][c]])
 79             ans += prob[c] * getProb(ac.ch[u][c], L-1);
 80     return ans;
 81 }
 82
 83 int main()
 84 {
 85     //freopen("in.txt", "r", stdin);
 86
 87     int T;
 88     scanf("%d", &T);
 89     for(int kase = 1; kase <= T; kase++)
 90     {
 91         int k, L;
 92         scanf("%d", &k);
 93         for(int i = 0; i < k; i++) scanf("%s", s[i]);
 94
 95         scanf("%d", &n);
 96         for(int i = 0; i < n; i++)
 97         {
 98             char s1[9];
 99             scanf("%s%lf", s1, &prob[i]);
100             idx[s1[0]] = i;
101         }
102
103         ac.init();
104         for(int i = 0; i < k; i++) ac.insert(s[i]);
105         ac.getFail();
106         scanf("%d", &L);
107         memset(vis, 0, sizeof(vis));
108         printf("Case #%d: %.6f\n", kase, getProb(0, L));
109     }
110
111     return 0;
112 }

代码君

时间: 2024-10-11 04:38:14

UVa 11468 (AC自动机 概率DP) Substring的相关文章

[AC自动机+概率dp] hdu 3689 Infinite monkey theorem

题意: 给n个字母,和m次数. 然后输入n个字母出现的概率 然后再给一个目标串str 然后问m次中敲出目标串的概率是多少. 思路: AC自动机+概率dp的简单题. 首先建立trie图,然后就是状态转移了 dp版本: dp三重循环变量次数,节点数,和字母数 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"

UVa 11468 Substring (AC自动机+概率DP)

题意:给出一个字母表以及每个字母出现的概率.再给出一些模板串S.从字母表中每次随机拿出一个字母,一共拿L次组成一个产度为L的串, 问这个串不包含S中任何一个串的概率为多少? 析:先构造一个AC自动机,然后随机生成L个字母,就是在AC自动机的某个结点走多少步,dp[i][j] 表示在 i 结点,并且剩下 j 步, 然后记忆化搜索就OK了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <

UVA 11468 Ac自动机+dp

题目意思:给出k个模式串,然后随机生成一个长度为L字符串,每个字符被选中的概率为pi  . 问构造出来的字符串不包含任何模式串的概率. 分析:显然这是一个模式串的母串的匹配,显然需要先构建一个AC自动机.我们用dp[i][j] 表示当前正在构造第i个字符,fail指针在j节点上能构造成功的概率.那么我们可以顺着fail指针向后面的状态. 注意只能扩展有效状态,也即不包含任何模式串的状态. 也即 dp [i][j]->dp[i+1][ch[j][k] ];  ch[j][k] 表示如果选k字符的话

bzoj1444 有趣的游戏(AC自动机+概率dp)

题意: 给定n个长度为l的模式串,现在要用前m个大写字母生成一个随机串,每个字符有自己的出现几率,第一次出现的字符串获胜,求最终每个字符串的获胜几率. 分析: 容易想到先把所有的字符串建成一个AC自动机 然后对于生成的随机串就相当于从AC自动机的root开始在自动机上走,然后求走到每个单词节点的概率 因为这是存在环的,不是DAG图,所以不能直接DP 考虑构造出刚开始的转移矩阵,然后对转移矩阵作矩阵乘法不断迭代就能得到正确答案了 转移矩阵如何建呢? 1)a[i][ch[i][j]]+=p[j] (

【BZOJ1444】[Jsoi2009]有趣的游戏 AC自动机+概率DP+矩阵乘法

[BZOJ1444][Jsoi2009]有趣的游戏 Description Input 注意 是0<=P Output Sample Input Sample Output HINT  30%的数据保证, n ≤ 2. 50%的数据保证, n ≤ 5. 100%的数据保证, n , l, m≤ 10. 题解:本题的做法真的很多啊,概率DP,期望DP,当然还有矩乘黑科技~ 就是先跑AC自动机,弄出转移矩阵,然后自乘50次就行了. #include <cstdio> #include <

【BZOJ4820】[Sdoi2017]硬币游戏 AC自动机+概率DP+高斯消元

[BZOJ4820][Sdoi2017]硬币游戏 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利.大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了.同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币,其他同学记录下正反面情况.用H表示正面朝上,用T表示反面朝上,扔很多次硬币后,会得到一个硬币序列.比如HTT表示第一次正面朝上,后两次反面朝上.但扔到什么时候停止呢?大家提议,选出n个同学,每个同学猜一个长度为m的序列,当某

POJ 3691 DNA repair 基于AC自动机的DP

dp[i][j] 表示长度为 i 的前缀到达第 j 个节点的最小更改数目. 很显然有dp[0][0] = 0; dp[ i ][ j ] = min(dp[ i ][ j ],dp[i-1][k] + (j == k ? 0 : 1)),当且仅当j,k满足下列条件时. j 不为某条模式串的末节点 且 j 到 root 的由失败指针组成的路径上无末节点. j 是k的儿子节点 或者 j 的父节点可由 k 沿着失败指针找到. #include <algorithm> #include <ios

HDU 4518 ac自动机+数位dp

吉哥系列故事--最终数 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 304    Accepted Submission(s): 102 Problem Description 在2012年腾讯编程马拉松比赛中,吉哥解决了一道关于斐波那契的题目,这让他非常高兴,也更加燃起了它对数学特别是斐波那契数的热爱.现在,它又在思考一个关于斐波那契

zoj 3494 BCD Code(AC自动机+数位dp)

题目链接:zoj 3494 BCD Code 题目大意:给定n个2进制串,然后有一个区间l,r,问说l,r之间有多少个数转换成BCD二进制后不包含上面的2进制串. 解题思路:AC自动机+数位dp.先对禁止串建立AC自动机,所有的单词节点即为禁止通行的节点.接着进行数位dp, 用solve(r) - solve(l-1), 这里的l需要用到大数减法.dp[i][j]表示第i为移动到节点j的可行方案数,每次枚举下一位数字,因 为是BCD二进制,所以每位数要一次性移动4个字符,中途有经过禁止点都是不行