uva 1358 - Generator(KMP+期望)

题目链接:uva 1358 - Generator

题目大意:给定n,表示有n中字符,然后给定一个字符串S,一开始字符串为空,现在每次随机生成一个1~n的字符添加到字符串末尾,问说字符串包含S为子串的生成次数期望。

解题思路:首先要对S进行预处理,求出失配数组。

定义dp[i]表示末尾部分匹配了i个S串所需要的次数期望,每次枚举可能出现的字符1~n。对于S字符串,i+1肯定是确定的字符,所以对于其他字符肯定是不匹配的。

假设现在生成了k字符,并且说k字符不等于S[i+1],那么根据S的失配数组,我们可以确定目前还匹配几个字符,(类似KMP匹配问题),假设有匹配j个字符,那么也就是说从匹配j个到匹配i个我们还要重新生成dp[i] - dp[j]次(期望)。

于是f(i)(从匹配i-1到匹配i个需要生成次数的期望)即有公式f(i)=1+∑i=1n(dp[i?1]?dp[lose(k)])+n?1nf(i)(lose(k)为对应生成字符为k的情况下还匹配的字符数)

dp[i] = dp[i-1] + f(i)

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

using namespace std;
typedef long long ll;

const int maxn = 20;

int len, jump[maxn];

void get_jump(char* s) {
    int p = 0;
    len = strlen(s+1);
    for (int i = 2; i <= len; i++) {
        while (p && s[p+1] != s[i])
            p = jump[p];

        if (s[p+1] == s[i])
            p++;
        jump[i] = p;
    }
}

ll solve () {
    int n;
    ll dp[maxn];
    char s[maxn];

    scanf("%d%s", &n, s+1);

    get_jump(s);
    dp[0] = 0;

    for (int i = 1; i <= len; i++) {

        ll& ans = dp[i];
        ans = dp[i-1] + n;

        for (int j = 0; j < n; j++) {
            if (s[i] == ‘A‘ + j)
                continue;

            int p = i-1;
            while (p && s[p+1] != j + ‘A‘)
                p = jump[p];

            if (s[p+1] == j + ‘A‘)
                p++;

            ans += dp[i-1] - dp[p];
        }
    }

    return dp[len];
}

int main () {
    int cas;
    scanf("%d", &cas);
    for (int kcas = 1; kcas <= cas; kcas++) {
        printf("Case %d:\n%lld\n", kcas, solve());

        if (kcas < cas)
            printf("\n");
    }
    return 0;
}
时间: 2024-10-20 01:39:29

uva 1358 - Generator(KMP+期望)的相关文章

UVA 1358 - Generator(dp+高斯消元+KMP)

UVA 1358 - Generator 题目链接 题意:有m种字符(从'A'开始往后数的大写字母),现在有一个字符串,长度不超过12,现在每次随机生成一个字母,要求能产生该字符串的期望长度 思路:dp[i]表示产生长度i的期望长度,那么每次产生一个字符,对应m种转移,每种转移的概率为1/m,转移后的长度可以利用KMP的next数组去快速获得,然后由于转移可能形成环的情况,所以无法直接DP,利用高斯消元去解方程组 代码: #include <cstdio> #include <cstri

UVA 11427 (概率DP+期望)

题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=35396 题目大意:每晚打游戏.每晚中,赢一局概率p,最多玩n局,如果最后不能保证胜率大于p,则从此不玩.问打游戏的天数的期望. 解题思路: 首先分析每天晚上的. 设f[i][j]为前i天,已经赢j局的概率. 由全概率公式,那么当天晚上完蛋的概率q=f[n][0]+f[n][1]+.....f[n][终止条件]. 至于为什么从完蛋(输)的角度考虑,主要是由于n局的

string (KMP+期望DP)

Time Limit: 1000 ms   Memory Limit: 256 MB Description  给定一个由且仅由字符 'H' , 'T' 构成的字符串$S$. 给定一个最初为空的字符串$T$ , 每次随机地在$T$的末尾添加 'H' 或者 'T' . 问当$S$为$T$的后缀时, 在末尾添加字符的期望次数. Input 输入只有一行, 一个字符串$S$. Output 输出只有一行, 一个数表示答案. 为了防止运算越界, 你只用将答案对$10^9+7$取模. Sample Inp

Hdu 1358 Period (KMP 求最小循环节)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1358 题目描述: 给出一个字符串S,输出S的前缀能表达成Ak的所有情况,每种情况输出前缀的结束位置和k. 解题思路: 打表算出next数组,然后对位置i求循环节,如果满足 i % (i - Next[i]) == 0 && Next[i] != 0,所对应的循环节(i - Next[i]), 循环次数是i / (i - Next[i]) 1 #include<cstdio> 2

HDU 1358 简单kmp

题目大意: 找到所有的可组成连续字符串相连的位置,和循环字符串的个数 #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <climits> #include <cmath> #include <cstdlib> using namespace std; #de

hdu 1358 period KMP入门

Period 题意:一个长为N (2 <= N <= 1 000 000) 的字符串,问前缀串长度为k(k > 1)是否是一个周期串,即k = A...A;若是则按k从小到大的顺序输出k即周期数: Sample Input 3 aaa 12 aabaabaabaab 0 Sample Output Test case #1 2 2 3 3 Test case #2 2   2 6   2 9   3 12  4 题目其实是来自于LA的..挺好的一道题,用的是原版的kmp.. 写写对KMP

UVA 1328 - Period KMP

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=36131 题意:给出一个长度为n的字符串,要求找到一些i,满足说从1~i为多个个的重复子串构成,并输出子串的个数. 题解:对kmp中预处理的数组的理解 //作者:1085422276 #include <cstdio> #include <cmath> #include <cstring> #include <ctime> #i

Period (poj 1961&amp;&amp;hdu 1358)KMP

Language: Default Period Time Limit: 3000MS   Memory Limit: 30000K Total Submissions: 13504   Accepted: 6365 Description For each prefix of a given string S with N characters (each character has an ASCII code between 97 and 126, inclusive), we want t

UVA.12230.Crossing Rivers(期望)

题目链接 /* 到达一条河时,船在河中的位置是随机的,所以船到达岸边需要的时间在 0~2l/v 均匀分布,所以船到岸的期望为 (0+2l/v)/2 过河需要 l/v 的时间,所以过一条河总的期望为 (0+2l/v)/2 + l/v = 2l/v 陆地上的速度是确定的,可以直接先计算出来 期望是线性的,每条河期望相加即为过河的总期望 */ #include<cstdio> using namespace std; int main() { int n,d,p,l,v,cas=0; while(~