【UVA】11468-Substring(AC自动机)

AC自动机的题,需要注意的,建立失配边的时候,如果结点1失配边连到的那个结点2,那个结点2是一个单词的结尾,那么这个结点1也需要标记成1(因为可以看成,这个结点包含了这个单词),之后在Trie树上进行行走,每次走到下一个可以走的结点。

14378527 11468 Substring Accepted C++ 0.585 2014-10-19 10:35:00

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 444;
const int max_size = 66;
const int maxd = 111;
int M,Case = 1;
int ch[max_size];
double P[max_size];
int index(int c){
    if(c >= 'A' && c <= 'Z') return c - 'A';
    if(c >= 'a' && c <= 'z') return c - 'a' + 26;
    if(c >= '0' && c <= '9') return c - '0' + 52;
}
struct Trie{
    int next[maxn][max_size];
    int fail[maxn];
    int val[maxn];
    int vis[maxn][maxd];
    double dp[maxn][maxd];
    int sz,root;
    int newnode(){
        val[sz] = 0;
        memset(next[sz],-1,sizeof(next[sz]));
        sz ++;
        return sz - 1;
    }
    void init(){
       sz = 0;
       root = newnode();
       memset(vis,0,sizeof(vis));
       return;
    }
    void insert(char *str){
        int now = root;
        int L = strlen(str);
        for(int i = 0; i < L; i++){
            int e = index(str[i]);
            if(next[now][e] == -1)
               next[now][e] = newnode();
            now = next[now][e];
        }
        val[now] = 1;
        return;
    }
    void build(){
        queue<int>q;
        fail[root] = root;
        for(int i = 0; i < max_size ; i++)
            if(next[root][i] != -1){
                fail[next[root][i]] = root;
                q.push(next[root][i]);
            }
            else
                next[root][i] = root;
        while(!q.empty()){
            int now = q.front(); q.pop();
            for(int i = 0; i < max_size ; i++){
                if(next[now][i] == -1)
                   next[now][i] = next[fail[now]][i];
                else{
                    q.push(next[now][i]);
                    fail[next[now][i]] = next[fail[now]][i];
                    val[next[now][i]] |= val[fail[next[now][i]]];
                }
            }
        }
        return;
    }
    double DP(int pos,int L){
        if(!L) return 1.0;
        if(vis[pos][L])
            return dp[pos][L];
        vis[pos][L] = 1;
        double &ans = dp[pos][L];
        ans = 0.0;
        for(int i = 0; i < M; i++){
            int e = ch[i];
            if(!val[next[pos][e]])
                ans += P[i] * DP(next[pos][e],L - 1);
        }
        return ans;
    }
}ac;
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ac.init();
        int K;
        scanf("%d",&K);
        for(int i = 0; i < K; i++){
            char str[maxn];
            scanf("%s",str);
            ac.insert(str);
        }
        ac.build();
        scanf("%d",&M);
        for(int i = 0; i < M; i++){
            char str[maxn];
            scanf("%s%lf",str,&P[i]);
            ch[i] = index(str[0]);
        }
        int L;
        scanf("%d",&L);
        double ans = ac.DP(0,L);
        printf("Case #%d: %.6f\n",Case++,ans);
    }
    return 0;
}
时间: 2024-10-11 16:55:34

【UVA】11468-Substring(AC自动机)的相关文章

UVA 11468 - Substring(AC自动机)

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

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

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

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】

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 &

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

题目链接:uva 1399 - Puzzle 题目大意:给定K和N,表示有K种不同的字符,N个禁止串,求一个最长的串使得该串不包含任何禁止串为子串.如果存在循环或者不能构成的话,输出No. 解题思路:建立AC自动机,然后在AC自动机上做dp,所有单词结尾节点为禁止点. #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std;

暑假 D6 T1 substring(AC自动机)

题目描述 给出一个长度为n的文本串,有Q次询问,每次给出一个字符串S,询问S是否在文本串中出现过 输入格式 第一行为两个整数n和Q,分别表示文本串长度和询问次数 第二行为长为n的文本串 接下来Q行,每行为一个字符串S 输出格式 输出Q行对应Q次询问的答案,若出现过则输出YES,否则输出NO 数据范围 对于100%的数据n,Q≤100000,且保证S为长度不超过100000的回文串,且所有的S的总长不超过1000000,保证所有字符都是小写字母. 题解 昨天才做了阿狸的打字机,就想到是一样的,而且

uva 11468 Substring

题意:给你 k 个模板串,然后给你一些字符的出现概率,然后给你一个长度 l ,问你这些字符组成的长度为 l 的字符串不包含任何一个模板串的概率. 思路:AC自动机+概论DP 首先用K个模板构造好AC自动机.题目上说长L的新串的子串不包含任何一个K串,其实就是说在构造好的树中,从根往下走L步都不包含K个模板.此题用match标记是否为K模板串. 状态转移方程代码中注释了. 1 #include<cstdio> 2 #include<cstring> 3 #include<que