Codeforces 482C Game with Strings

来源:互联网 发布:桌面显示激活windows 编辑:程序博客网 时间:2024/04/29 03:47

题目描述

You play the game with your friend. The description of this game is listed below.

Your friend creates n distinct strings of the same length m and tells you all the strings. Then he randomly chooses one of them. He chooses strings equiprobably, i.e. the probability of choosing each of the n strings equals . You want to guess which string was chosen by your friend.

In order to guess what string your friend has chosen, you are allowed to ask him questions. Each question has the following form: «What character stands on position pos in the string you have chosen?» A string is considered guessed when the answers to the given questions uniquely identify the string. After the string is guessed, you stop asking questions.

You do not have a particular strategy, so as each question you equiprobably ask about a position that hasn’t been yet mentioned. Your task is to determine the expected number of questions needed to guess the string chosen by your friend.

Input
The first line contains a single integer n (1 ≤ n ≤ 50) — the number of strings your friend came up with.

The next n lines contain the strings that your friend has created. It is guaranteed that all the strings are distinct and only consist of large and small English letters. Besides, the lengths of all strings are the same and are between 1 to 20 inclusive.

Output
Print the single number — the expected value. Your answer will be considered correct if its absolute or relative error doesn’t exceed 10 - 9.

题意

给你n个字符串,其中有一个串是正确答案,每次你可以询问第i个位置的字母是什么,问最后猜出答案的期望的步数。

思路

d[i](用m位二进制表示第j个字母是否被猜)代表在已猜的字符位置在i的状态下,仍然不能猜出的字符串(用N位二进制表示第k个字符串是否已被猜出)

显然有:

d[mask ^ (1 << i)] |= d[mask];

根据这个式子能把d数组求出来

然后是计数:

你希望求出在moves步数下新猜出的字符串个数,那么就枚举当前的状态mask,然后枚举最后猜的位置i,那么:

res = d[mask] ^ d[mask ^ (1 << i)];

最后求期望:

枚举步数i,对答案的贡献为:

totalGuessed[i]/C(m,i)/n

官方题解

Let’s handle all string pairs and calculate the mask mask, which will have 1-bits only in positions in which that strings have the same characters. In other words, we could not distinguish these strings using positions with submask of mask mask, then we must add in d[mask] 1-bits in positions i и j. This way in d[mask] we store mask of strings, which we could not distinguish using only positions given in mask mask. Using information described above, we can easily calculate this dynamics.
Now, when we have array d calculated, it is not hard to calculate the answer. Let’s handle some mask mask. Now we should try to make one more question in position pos, which is equal to adding one more 1-bit in mask in position pos. After that we may guess some strings, they are 1-bits in mask s = d[mask] ^ d[mask | (1 << pos)]. Then you have to calculate number of bits in s quickly and update the answer.

代码

#include <cstdio>#include <iostream>#include <cstring>#include <iomanip>#include <algorithm>#include <ctime>using namespace std;const int N = 20;const int M = 150;int n;char s[M][N + 10];typedef long long li;typedef long double ld;li d[(1 << N)];inline bool has(li mask, int pos) {    return (mask >> pos) & 1;}ld prob[N + 10];ld totalGuessed[N + 10];int main() {    int n;    scanf("%d", &n);    for(int i = 0; i < n; i++) {        scanf("%s", s[i]);    }  int m = strlen(s[0]);    for(int i = 0; i < n; i++) {        for(int j = 0; j < n; j++) {            if (i == j) continue;            int same = 0;            for(int k = 0; k < m; k++) {                if (s[i][k] == s[j][k]) same |= (1 << k);            }            d[same] |= (1LL << i);        }    }    for(int mask = (1 << m) - 1; mask; mask--) {        for(int i = 0; i < m; i++) {            if (has(mask, i)) {                d[mask ^ (1 << i)] |= d[mask];            }           }    }    long double ans = 0;    for(int mask = 0; mask < (1 << m); mask++) {        int moves = __builtin_popcount(mask) + 1;        for(int i = 0; i < m; i++) {            if (!has(mask, i)) {                li res = d[mask] ^ d[mask ^ (1 << i)];                if (res == 0) continue;                int cntGuessed = __builtin_popcountll(res);                totalGuessed[moves] += cntGuessed;            }        }    }    for(int i = 1; i <= m; i++) {        ld val = totalGuessed[i] * i;        for(int j = 0; j < i - 1; j++)             val *= ld(i - 1 - j) / ld(m - j);        ans += val / ld(m - i + 1);    }    ans /= ld(n);    cerr << clock() << endl;    cout << fixed << setprecision(15) << ans << endl;}
0 0