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

题目链接:uva 11468 - Substring

题目大意:给出一些字符和各自字符对应的选择概率,随机选择L次后得到一个长度为L的字符串,要求该字符串不包含任意一个子串的概率。

解题思路:构造AC自动机之后,每随机生成一个字母,等于是在AC自动机上走一步,所有子串的结束位置的节点标记为禁止通行,然后问题转换成记忆搜索处理。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>

using namespace std;

const int sigma_size = 62;
const int maxn = 405;;

double pi[sigma_size], dp[maxn][105];
int vis[maxn][105];

int sz;
int ac[maxn][sigma_size];
int fail[maxn], last[maxn];

inline int idx (char ch) {
    if (ch >= ‘0‘ && ch <= ‘9‘)
        return ch - ‘0‘;
    if (ch >= ‘a‘ && ch <= ‘z‘)
        return ch - ‘a‘ + 10;
    if (ch >= ‘A‘ && ch <= ‘Z‘)
        return ch - ‘A‘ + 36;
    return 0;
}

void ahoc_insert (char *s) {
    int u = 0, n = strlen(s);
    for (int i = 0; i < n; i++) {
        int v = idx(s[i]);

        if (ac[u][v] == 0) {
            last[sz] = 0;
            memset(ac[sz], 0, sizeof(ac[sz]));
            ac[u][v] = sz++;
        }
        u = ac[u][v];
    }
    last[u] = 1;
}

void ahoc_fail () {
    queue<int> que;

    for (int i = 0; i < sigma_size; i++) {
        int u = ac[0][i];
        if (u) {
            fail[u] = 0;
            que.push(u);
        }
    }

    while (!que.empty()) {
        int r = que.front();
        que.pop();

        for (int i = 0; i < sigma_size; i++) {
            int u = ac[r][i];

            if (u == 0) {
                ac[r][i] = ac[fail[r]][i];
                continue;
            }

            que.push(u);
            int v = fail[r];

            while (v && !ac[v][i])
                v = fail[v];
            fail[u] = ac[v][i];
            last[u] |= last[fail[u]];
        }
    }
}

void init () {
    int n, x;
    char str[sigma_size];
    memset(pi, 0, sizeof(pi));
    memset(vis, 0, sizeof(vis));

    sz = 1;
    fail[0] = last[0] = 0;
    memset(ac[0], 0, sizeof(ac[0]));

    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%s", str);
        ahoc_insert(str);
    }
    ahoc_fail();

    scanf("%d", &n);
    for (int i = 0; i < n; i++)  {
        scanf("%s", str);
        scanf("%lf", &pi[idx(str[0])]);
    }
}

double getProb (int u, int dep) {
    if (dep == 0)
        return 1.0;

    if (vis[u][dep])
        return dp[u][dep];

    vis[u][dep] = 1;

    double& ans = dp[u][dep];
    ans = 0;

    for (int i = 0; i < sigma_size; i++) {
        if (last[ac[u][i]] == 0)
            ans += pi[i] * getProb(ac[u][i], dep - 1);
    }
    return ans;
}

int main () {
    int cas;
    scanf("%d", &cas);
    for (int kcas = 1; kcas <= cas; kcas++) {
        init();

        int n;
        scanf("%d", &n);
        printf("Case #%d: %.6lf\n", kcas, getProb(0, n));
    }
    return 0;
}
时间: 2024-10-13 14:23:58

uva 11468 - Substring(AC自动机+概率)的相关文章

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 - Substring(AC自动机)

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

UVA 11468【AC自动机+DP】

dp[i][j]表示走了i步走到j结点的概率.初始值dp[0][0] = 1.当走到的结点不是单词尾结点时,才能走过去. !end[i]&&last[i] == root时,该结点才可行. 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 505; 4 int id(char c){ 5 if(c >= '0'&&c <= '9') return c-'0'; 6 if

UVA 1399 - Puzzle(AC自动机+DP)

UVA 1399 - Puzzle 题目链接 题意:给定一些字符串,求一个最长的不在包含这些子串的字符串,如果可以无限长输出No 思路:建ACM自动机,把不可走结点标记构造出来,然后在这个状态图上进行dp找出最长路径即可,至于无限长的情况,只要在dp前进行一次dfs判有没有环即可 代码: #include <cstdio> #include <cstring> #include <string> #include <algorithm> #include &

[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 (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自动机)

用把失配边也加到正常边以后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_Substring_(AC自动机+概率动态规划)

描述 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2463 给出一些子串.然后给出一些字符,以及每个字符出现的概率.现在用这些字符组成一个长度为s的字符串,问之前给出的子串都没有在这个字符串中出现的概率是多少. 分析 边选字母边匹配.只要前面的字串都不能匹配成功即可.用前面的那些子串造出个AC自动机,然后在上面跑.用match数组表示每