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 ch[NODE][SIZE], fail[NODE], match[NODE], sz;
    void clear(void)    {
        memset (ch[0], 0, sizeof (ch[0]));
        sz = 1;
    }
    void insert(char *P)    {
        int u = 0, lenp = strlen (P);
        for (int c, i=0; i<lenp; ++i)    {
            c = idx[P[i]];
            if (!ch[u][c])  {
                memset (ch[sz], 0, sizeof (ch[sz]));
                match[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        match[u] = 1;
    }
    void build(void)    {
        queue<int> que; fail[0] = 0;
        int u;
        for (int c=0; c<SIZE; ++c)  {
            u = ch[0][c];
            if (u)  {
                fail[u] = 0;    que.push (u);
            }
        }
        while (!que.empty ())   {
            int r = que.front ();   que.pop ();
            for (int c=0; c<SIZE; ++c)  {
                int u = ch[r][c];
                if (!u) {
                    ch[r][c] = ch[fail[r]][c]; continue;
                }
                que.push (u);
                int v = fail[r];
                while (v && !ch[v][c])    v = fail[v];
                fail[u] = ch[v][c];
                match[u] |= match[fail[u]];
            }
        }
    }
}ac;

double prob[SIZE];
bool vis[NODE][L];
double dp[NODE][L];
double DFS(int u, int len)  {
    if (!len)   return 1.0;
    if (vis[u][len])    return dp[u][len];
    vis[u][len] = true;
    double &ret = dp[u][len];
    ret = 0;
    for (int i=0; i<n; ++i) {
        if (!ac.match[ac.ch[u][i]]) ret += prob[i] * DFS (ac.ch[u][i], len - 1);
    }
    return ret;
}
char pattern[30][30];
//char pattern[30];

int main(void)  {
    int T, cas = 0;  scanf ("%d", &T);
    while (T--) {
        //char pattern[30];
        ac.clear ();
        int k;  scanf ("%d", &k);
        for (int i=1; i<=k; ++i)    {
            scanf ("%s", &pattern[i]);
            //scanf ("%s", &pattern);
            //ac.insert (pattern);
        }
        //ac.build ();
        scanf ("%d", &n);
        char str[3];
        for (int i=0; i<n; ++i)    {
            scanf ("%s%lf", &str, &prob[i]);
            idx[str[0]] = i;
        }
        for (int i=1; i<=k; ++i)    ac.insert (pattern[i]);
        ac.build ();
        int len;    scanf ("%d", &len);
        memset (vis, false, sizeof (vis));
        printf ("Case #%d: %.6lf\n", ++cas, DFS (0, len));
    }

    return 0;
}

  

时间: 2024-12-15 02:17:22

AC自动机+全概率+记忆化DP UVA 11468 Substring的相关文章

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

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

UVA - 11324 The Largest Clique 强连通缩点+记忆化dp

题目要求一个最大的弱联通图. 首先对于原图进行强连通缩点,得到新图,这个新图呈链状,类似树结构. 对新图进行记忆化dp,求一条权值最长的链,每个点的权值就是当前强连通分量点的个数. /* Tarjan算法求有向图的强连通分量set记录了强连通分量 Col记录了强连通分量的个数. */ #include <iostream> #include<cstring> #include<cstdio> #include<string> #include<algo

UVA 11468 - Substring(AC自动机)

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

cf779D(记忆化dp)

题目链接: http://codeforces.com/problemset/problem/799/D 题意: 给出两个矩阵边长 a, b, 和 w, h, 以及一个 c 数组, 可选择 c 数组中任意数字乘上w 或 h. 数组中每个数字最多只能用一次. 求最少选择多少个数字可使得边长为 a, b 的矩阵能放到变化后的矩阵中. 思路: log2(1e5) = 17, 即最多需要对一条边乘17个数字, 要是完全暴力的话需要 2^34 的时间复杂度, 显然不行. 本题 dp 可解, 先给 c 降序

LightOJ 1038 Race to 1 Again 期望 记忆化dp

题目链接:点击打开链接 1038 - Race to 1 Again PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB Rimi learned a new thing about integers, which is - any positive integer greater than 1 can be divided by its divisors. So, he is now playin

POJ 1088 滑雪(简单的记忆化dp)

题目 又一道可以称之为dp的题目,虽然看了别人的代码,但是我的代码写的还是很挫,,,,,, //看了题解做的简单的记忆化dp #include<stdio.h> #include<algorithm> #include<iostream> using namespace std; int mp[110][110],dp[110][110]; int xx[]={1,-1,0,0}; int yy[]={0,0,1,-1}; int n,m; int dfs(int x,

BNU 25593 Prime Time 记忆化dp

题目链接:点击打开链接 题意: 一个游戏由3个人轮流玩 每局游戏由其中一名玩家选择一个数字作为开始 目的:获得最小的得分 对于当前玩家 O ,面对 u 这个数字 则他的操作有: 1. 计分 u +1 ,然后 u++; 2.计分 u / x, 然后 u /= x; 其中x为u的因子且x为素数 然后下一个玩家继续上述操作 3个人各操作一次 为1轮 当一轮结束后,若u==1 则游戏结束 每个人的得分为 他所有计分记录里最小的数字 若在一轮结束前 u就==1, 那么玩家的得分为本局游戏的初始数 求: 每

poj1692(区间记忆化dp)

题意:上下两行数相连,相等的才可以相连,并且每条线必须且只能与其他一条线相交(要同时满足相交的两条线的数不相等).问给的两行数最多可以连几条线. 解法:ans[i][j]记录着上面i,和下面j下标之后的数中最多可以连多少条,记忆化搜索dfs(0,0)就可以了.搜索时候,如果用到了i,则贪心在下面选相等的.用到j同理. 代码: /**************************************************** * author:xiefubao **************

Google Code Jam 2009, Round 1C C. Bribe the Prisoners (记忆化dp)

Problem In a kingdom there are prison cells (numbered 1 to P) built to form a straight line segment. Cells number i and i+1 are adjacent, and prisoners in adjacent cells are called "neighbours." A wall with a window separates adjacent cells, and