Codeforces 482C Game with Strings(dp+概率)

题目链接:Codeforces 482C Game with Strings

题目大意:给定N个字符串,现在从中选定一个字符串为答案串,你不知道答案串是哪个,但是可以通过询问来确定,

每次询问一个位置上字符为多少。现在你询问的每个位置的概率是相同的,(问过的位置不会再问),求询问次数的期

望。

解题思路:因为字符串长度不会大于20,所以用二进制表示询问了哪些位置,C[s]即为询问s的位置可以确定多少个字

符串。这步不能通过枚举s,然后判断处理,复杂度为o(2^20 * 20 * 50),太高。可以通过枚举两个字符串,判断它们哪些

位置相同,则在对应的s状态下标记这两个字符串无法被区分,最后在遍历一遍s状态递推一次,因为如果s1状态包含s2

状态,那么s2状态下不能区分的字符串同样在s1状态无法区分。

确定每个状态下可区分字符串的个数之后就好做了,dp[s]表示移动到状态s后还要继续判断的概率,不用继续判断的直

接加到对应的步数中。

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

using namespace std;
typedef long long ll;
typedef pair<ll, int> pii;
const int maxs = (1<<20) + 5;
const int maxn = 55;
const int maxm = 25;
const ll x = 123;

int N, L, T, C[maxs];
ll D[maxs];
char str[maxn][maxm];

inline int idx(char ch) {
    if (ch >= ‘a‘ && ch <= ‘z‘)
        return ch - ‘a‘;
    return ch - ‘A‘ + 26;
}

inline int bitcount(ll x) {
    return x == 0 ? 0 : bitcount(x>>1) + (x&1);
}

void init () {
    scanf("%d", &N);
    for (int i = 0; i < N; i++)
        scanf("%s", str[i]);
    L = strlen(str[0]);
    T = (1<<L);

    for (int i = 0; i < N; i++) {
        for (int j = i + 1; j < N; j++) {
            int s = 0;
            for (int k = 0; k < L; k++)
                s |= (str[i][k] == str[j][k]) << k;
            D[s] |= (1LL<<i) | (1LL<<j);
        }
    }

    for (int i = T-1; i; i--) {
        for (int j = 0; j < L; j++)
            if (i&(1<<j))
                D[i^(1<<j)] |= D[i];
        C[i] = N - bitcount(D[i]);
    }
}

double dp[maxs], p[100];

int main () {
    init();

    if (N == 1) {
        printf("%.9lf\n", 0.0);
        return 0;
    }

    dp[0] = 1;
    for (int u = 0; u < T; u++) {
        int bit = bitcount(u), sum = N - C[u];
        double mv = dp[u] / (L - bit);
        if (N == C[u]) continue;

        for (int i = 0; i < L; i++) {
            if (u&(1<<i))
                continue;
            int s = u | (1<<i);
            double a = 1.0 * (C[s] - C[u]) / sum;

            dp[s] += mv * (1 - a);
            p[bit+1] += mv * a;
        }
    }

    /*
    double sum = 0;
    for (int u = 1; u <= L; u++) {
        printf("%lf\n", p[u]);
        sum += p[u];
    }
    printf("%lf!\n", sum);
    */

    double ans = 0;
    for (int i = 1; i <= L; i++)
        ans += p[i] * i;
    printf("%.9lf\n", ans);
    return 0;
}
时间: 2024-08-06 02:11:01

Codeforces 482C Game with Strings(dp+概率)的相关文章

Codeforces 360C Levko and Strings dp

题目链接:点击打开链接 题意: 给定长度为n的字符串s,常数k 显然s的子串一共有 n(n-1)/2 个 要求找到一个长度为n的字符串t,使得t对应位置的k个子串字典序>s #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<vector> #include<set> using namespace std; #

Codeforces 482C. Game with Strings 状压DP

很好的状压dp题目 d[mask]=x   在询问了mask位的情况下,有x状态的串还是不能区分 /// 预处理不好会TLE dp[x]  从一次也没有问,到问到状态x时的概率 可以看 http://blog.csdn.net/houserabbit/article/details/40658791 大神的题解 C. Game with Strings time limit per test 1 second memory limit per test 256 megabytes input s

CodeForces 482C Game with Strings

题意: n个长为m的字符串  等概率的藏起来一个串  然后游戏者来猜藏起来的串是什么  每一步游戏者可以等概率的询问字符串的一个位置  再不断的知道一些位置后  游戏者就可以确定藏起来的串是什么  问  游戏者的期望步数 思路: 可以说是一道概率题  也可以说是期望题  总之感觉题目不错- 首先如果我们枚举藏起来的串是哪个(复杂度n)  然后利用状压去dp维护猜某些位的状态的概率  以及对于那个状态剩下哪些串是无法辨别的(复杂度m*2^m)  那么复杂度为 O(nm2^m) 这样就会TLE 接着

codeforces 235B Let&#39;s Play Osu! 概率dp

题意:给定n表示有n个格子,下面每个格子为O的概率是多少.对于一段连续 x 个O的价值就是 x^2 ;求获得的价值的期望是多少. 思路:n^2=n×(n-1)+n,设ai为第i段连续O的长度,∑ai^2 = ∑[ ai+ ai*(ai-1) ] = ∑ ai*(ai-1) + ∑ai = ∑ C(ai, 2)*2 + ∑ai,那么问题可以转 化为求长度大于1的连续段数*2+O的个数的总期望. ∑ai我们可以理解为O的总个数,所以它的期望为∑pi: C(ai, 2)*2我们可以认 为是连续ai个O

Codeforces 235B Let&#39;s Play Osu! (概率dp求期望+公式变形)

B. Let's Play Osu! time limit per test:2 seconds memory limit per test:256 megabytes You're playing a game called Osu! Here's a simplified version of it. There are n clicks in a game. For each click there are two outcomes: correct or bad. Let us deno

Codeforces 235B Let&#39;s Play Osu! 概率dp(水

题目链接:点击打开链接 给定n表示有n个格子 下面每个格子为O的概率是多少. 对于一段连续 x 个O的价值就是 x*x ; 问: 获得的价值的期望是多少. 思路: 把公式拆一下.. #include <cstdio> const int N = 100005; double dp[N][2], p[N]; int main(){ int n; scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("

[2016-03-23][codeforces][560][D][Equivalent Strings]

时间:2016-03-23 14:15:39 星期三 题目编号:[2016-03-23][codeforces][560][D][Equivalent Strings] 题目大意:定义两个字符串相等方式,给出两个字符串,问是否相等 分析:递归判断即可 遇到的问题:长度为奇数的字符串一定不相等 #include <iostream> #include <string> using namespace std; int issame(string str1,string str2){

UVA 11427 Expect the Expected(DP+概率)

链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=35396 [思路] DP+概率 见白书. [代码] 1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 5 const int N = 100+10; 6 7 int n,a,b; 8 double f[N][N]; 9 10 int main() { 11 int T,kase=

CF235 Let&#39;s Play Osu![dp+概率]

题意: 给n个位置,给出1-n上每个位置出现O的概率pi,记分规则如下,连续的x个O记为x^2分,求和,如 XXOOOXOXOOXX得分为 求得分的期望 思考一下,我们能比较容易地得出O(n^2)的方法 令dp[i]为前i的得分期望 那么 显然这题 考虑一下变换记分的方式 我们有 那么记分方式就变为 一段连续的O,有多少对O×2+O的个数 一对O可以贡献2分 现在得分来源变为两个地方 一对O(2分),和单个O(1分) 我们知道 期望=概率×收益 我们找到每个对O的概率×2 再找到单个O×出现概率