uva 11468 Substring

题意:给你 k 个模板串,然后给你一些字符的出现概率,然后给你一个长度 l ,问你这些字符组成的长度为 l 的字符串不包含任何一个模板串的概率。

思路:AC自动机+概论DP

首先用K个模板构造好AC自动机。题目上说长L的新串的子串不包含任何一个K串,其实就是说在构造好的树中,从根往下走L步都不包含K个模板。此题用match标记是否为K模板串。

状态转移方程代码中注释了。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<cstdio>
  5 #include<map>
  6 #include<string>
  7 using namespace std;
  8
  9 const int SIGMA_SIZE = 64;
 10 const int MAXNODE = 500; // 结点总数
 11 const int MAXS = 20 + 10; // 模板个数
 12
 13 int idx[256], n;
 14 double prob[SIGMA_SIZE];
 15
 16 struct AhoCorasickAutomata
 17 {
 18     int ch[MAXNODE][SIGMA_SIZE];
 19     int f[MAXNODE];    // fail函数
 20     int match[MAXNODE];  // 是否包含某一个字符串
 21     int sz;            // 结点总数
 22
 23     void init()
 24     {
 25         sz = 1;
 26         memset(ch[0], 0, sizeof(ch[0]));
 27     }
 28
 29     // 插入字符串
 30     void insert(char *s)
 31     {
 32         int u = 0, n = strlen(s);
 33         for(int i = 0; i < n; i++)
 34         {
 35             int c = idx[s[i]];
 36             if(!ch[u][c])
 37             {
 38                 memset(ch[sz], 0, sizeof(ch[sz]));
 39                 match[sz] = 0;
 40                 ch[u][c] = sz++;
 41             }
 42             u = ch[u][c];
 43         }
 44         match[u] = 1;
 45     }
 46
 47     // 计算fail函数
 48     void getFail()
 49     {
 50         queue<int> q;
 51         f[0] = 0;
 52         // 初始化队列
 53         for(int c = 0; c < SIGMA_SIZE; c++)
 54         {
 55             int u = ch[0][c];
 56             if(u)
 57             {
 58                 f[u] = 0;
 59                 q.push(u);
 60             }
 61         }
 62         // 按BFS顺序计算fail
 63         while(!q.empty())
 64         {
 65             int r = q.front();
 66             q.pop();
 67             for(int c = 0; c < SIGMA_SIZE; c++)
 68             {
 69                 int u = ch[r][c];
 70                 if(!u)
 71                 {
 72                     ch[r][c] = ch[f[r]][c];
 73                     continue;
 74                 }
 75                 q.push(u);
 76                 int v = f[r];
 77                 while(v && !ch[v][c]) v = f[v];
 78                 f[u] = ch[v][c];
 79                 match[u] |= match[f[u]];
 80             }
 81         }
 82     }
 83 };
 84
 85 AhoCorasickAutomata ac;
 86
 87 double d[MAXNODE][105];
 88 int vis[MAXNODE][105];
 89
 90 double getProb(int u, int L)//d[u][L]=prob[u]*d[v][L-1]状态转方程 v为u的儿子可以走节点
 91 {
 92     if(!L) return 1.0;
 93     if(vis[u][L])
 94         return d[u][L];
 95     vis[u][L] = 1;
 96     d[u][L]=0.0;
 97     for(int i = 0; i < n; i++)
 98         if(!ac.match[ac.ch[u][i]])
 99             d[u][L] += prob[i] * getProb(ac.ch[u][i], L-1);
100     return d[u][L];
101 }
102
103 char s[30][30];
104
105 int main()
106 {
107     int T;
108     scanf("%d", &T);
109     for(int kase = 1; kase <= T; kase++)
110     {
111         int k, L;
112         scanf("%d", &k);
113         for(int i = 0; i < k; i++) scanf("%s", s[i]);
114         scanf("%d", &n);
115         for(int i = 0; i < n; i++)
116         {
117             char ch[9];
118             scanf("%s%lf", ch, &prob[i]);
119             idx[ch[0]] = i;
120         }
121         ac.init();
122         for(int i = 0; i < k; i++) ac.insert(s[i]);
123         ac.getFail();
124         scanf("%d", &L);
125         memset(vis, 0, sizeof(vis));
126         memset(d,0,sizeof(d));
127         printf("Case #%d: %.6lf\n", kase, getProb(0, L));
128     }
129     return 0;
130 }

时间: 2024-10-05 08:27:15

uva 11468 Substring的相关文章

uva 11468 - Substring(AC自动机+概率)

题目链接:uva 11468 - Substring 题目大意:给出一些字符和各自字符对应的选择概率,随机选择L次后得到一个长度为L的字符串,要求该字符串不包含任意一个子串的概率. 解题思路:构造AC自动机之后,每随机生成一个字母,等于是在AC自动机上走一步,所有子串的结束位置的节点标记为禁止通行,然后问题转换成记忆搜索处理. #include <cstdio> #include <cstring> #include <queue> #include <algor

UVA 11468 - Substring(AC自动机)

UVA 11468 - Substring 题目链接 题意:给定一些模式串,然后给出一些字母出现的概率,每次随机出现一个字母,要求出这些字母出现L个组成的字符串不包含(即不是它的连续字串)已有模式串的概率 思路:AC自动机,先构造出AC自动机,构造的时候利用next数组的特性,记录下每个位置是否有经过一个单词结点,如果有这个结点就是不能走的结点,那么问题就变成了只能在能走的结点上走L步的概率,注意这里空边也要处理成可以走(走到它的next,因为不匹配的话就一直找到next能匹配的位置),然后进行

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 <

AC自动机+全概率+记忆化DP UVA 11468 Substring

题目传送门 题意:训练之南P217 分析:没有模板串也就是在自动机上走L步,不走到val[u] == v的节点的概率 PS:边读边insert WA了,有毒啊! #include <bits/stdc++.h> using namespace std; const int K = 20 + 5; const int L = 100 + 5; const int NODE = K * K; const int SIZE = 66; int idx[256], n; struct AC { int

UVA 11468 Substring (AC自动机)

用把失配边也加到正常边以后AC自动机,状态是长度递减的DAG,每个选一个不会匹配字符的转移. dp[u][L]表示当前在tire树上u结点长度还剩L时候不匹配的概率,根据全概率公式跑记忆化搜索. #include<bits/stdc++.h> using namespace std; typedef double ld; const int maxnds = 21*21, sigma_size = 62; int nds; int ch[maxnds][sigma_size]; double

UVA 11468 Substring (记忆化搜索 + AC自动鸡)

传送门 题意: 给你K个模式串, 然后,再给你 n 个字符, 和它们出现的概率 p[ i ], 模式串肯定由给定的字符组成. 且所有字符,要么是数字,要么是大小写字母. 问你生成一个长度为L的串,不包含任何模式串的概率是多少. 解: 记忆化搜索 +  AC自动机. 对模式串建一个AC自动机, 不需要last[ ] 和 val[ ], 只需要一个 metch[ ]. 维护一下这个点是否是某个模式串的最后一个字符节点,若是,则这个点不能走. 然后, 剩下的就是从根节点,随便走 L 步, 记得要记忆化

Uva 11468 改良版AC自动机

改良版AC自动机 UVa 11468 题意:给一些字符和各自出现的概率,在其中随机选择L次,形成长度为L的字符串S,给定K个模板串,求S不包含任意一个串的概率. 首先介绍改良版的AC自动机: 传统的AC自动机,是当一个字符失配时,根据失配函数转移到指定地方,而这个失配函数,是通过一个宽搜的过程形成的,这时在匹配串的时候,就当匹配失败时,顺着失配指针走,直到可以匹配.然后匹配到单词结点,或者后缀链接是一个单词结点,这些前面的结点也是匹配单词.这就是传统的AC自动机. 现在将这个AC自动机改版优化:

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[2

UVA 11468(Substring-AC自动机上dp)[Template:AC自动机]

Substring Given a set of pattern strings, and a text, you have to find, if any of the pattern is a substring of the text. If any of the pattern string can be found in text, then print "yes", otherwise "no" (without quotes). But, unfort