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

standard input

output

standard output

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.

Sample test(s)

input

2
aab
aac

output

2.000000000000000

input

3
aaA
aBa
Caa

output

1.666666666666667

input

3
aca
vac
wqq

output

1.000000000000000

Note

In the first sample the strings only differ in the character in the third position. So only the following situations are possible:

  • you guess the string in one question. The event‘s probability is ;
  • you guess the string in two questions. The event‘s probability is  ·  =  (as
    in this case the first question should ask about the position that is other than the third one);
  • you guess the string in three questions. The event‘s probability is  ·  ·  = ;

Thus, the expected value is equal to 

In the second sample we need at most two questions as any pair of questions uniquely identifies the string. So the expected number of questions is .

In the third sample whatever position we ask about in the first question, we immediately identify the string.

/* ***********************************************
Author        :CKboss
Created Time  :2015年03月08日 星期日 21时18分00秒
File Name     :CF482C_C.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

typedef long long int LL;

char str[55][22];

int n,m;
LL d[(1<<20)+10];
double dp[(1<<20)+10];

int countb(LL x)
{
	int ans=0;
	while(x) { ans++; x=x&(x-1LL); }
	return ans;
}

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);

	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%s",str[i]);
	m=strlen(str[0]);

	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			if(j==i) continue;
			/// string i and string j has public pos
			int same=0;
			for(int k=0;k<m;k++)
			{
				if(str[i][k]==str[j][k]) same|=(1<<k);
			}
			d[same]|=(1LL<<i); d[same]|=(1LL<<j);
		}
	}
	// d[mask] <= d[mask^(1<<i)]
	for(int mask=(1<<m)-1;mask;mask--)
	{
		for(int j=0;j<m;j++)
		{
			if((mask>>j)&1)
			{
				int nmask=mask^(1<<j);
				d[nmask]|=d[mask];
			}
		}
	}

	dp[0]=1;
	double ans=0;
	for(int mask=0;mask<(1<<m);mask++)
	{
		int c=countb(mask);
		for(int j=0;j<m;j++)
		{
			if(((mask>>j)&1)==0)
			{
				int nmask=mask|(1<<j);
				dp[nmask]+=dp[mask]/(m-c);
			}
		}
		for(int j=0;j<n;j++)
		{
			if((d[mask]>>j)&1LL) ans+=dp[mask];
		}
	}

	printf("%.15lf\n",ans/n);

    return 0;
}
时间: 2024-10-09 10:05:51

Codeforces 482C. Game with Strings 状压DP的相关文章

Codeforces 544E Remembering Strings 状压dp

题目链接 题意: 给定n个长度均为m的字符串 下面n行给出字符串 下面n*m的矩阵表示把对应的字母修改成其他字母的花费. 问: 对于一个字符串,若它是easy to remembering 当 它存在一个字母,使得这个字母在这一列是独一无二的. 要使得n个字符串都是easy to remembering 的最小花费. 第一个样例是把第一列的4个a中3个a修改成别的字母,所以花费为3. 思路: 显然是个状压dp,但需要一点转化. 首先得到一个结论: 对于某一列,设这一列的字母是 a,a,b,b,a

Codeforces Gym 100676G Training Camp 状压dp

http://codeforces.com/gym/100676 题目大意是告诉你要修n门课,每门课有一个权值w[i], 在第k天修该课程讲获得k*w[i]的学习点数,给出了课程与先修课程的关系,要修该课程必须修完先修课程.问最多能学到多少点数. 非常简单的一道状压dp(一开始我还误导队友写成两维的去了 T^T); dp[s] : s 的二进制存放的是已经选择的课程,在该状态下的能获得的最大的点数. 这时如果再学一门课程k,将转移到状态ss (s | (1 << k) ) ,能否转移需要判断合

Codeforces 11D - A Simple Task (状压DP)

题意 求出一个n个点m个边的图,求简单环有多少(没有重复点和边). 思路 这是个不错的题,这个状压dp保存的状态不是直接的环,而是路径的个数.s表示的状态为一条路径,则dp[s][i]表示以s的最小编号为起点,以i为终点的环的个数.那么我们就可以通过枚举状态,枚举状态中的起点和枚举路径外的终点,然后判断终点和起点是否相连来判断是否成环. 代码 #include <stdio.h> #include <string.h> #include <iostream> #incl

Codeforces 895C Square Subsets(状压DP 或 异或线性基)

题目链接  Square Subsets 这是白书原题啊 先考虑状压DP的做法 2到70总共19个质数,所以考虑状态压缩. 因为数据范围是70,那么我们统计出2到70的每个数的个数然后从2考虑到70. 设dp[x][mask]为考虑到x这个数的时候,x这个数和之前的所有数中,选出某些数,他们的乘积分解质因数,所有的指数对2取模之后, 状态为mask的方案数. 然后就可以转移了……这个状压DP花了我好几个小时……真是弱啊 哦对最后还要特判1的情况. 每个1选或不选都可以,然后考虑只选1的情况,累加

CF482C Game with Strings (状压DP+期望DP)

题目大意:甲和乙玩游戏,甲给出n(n<=50)个等长的字符串(len<=20),然后甲选出其中一个字符串,乙随机询问该字符串某一位的字符(不会重复询问一个位置),求乙能确定该串是哪个字符串的询问次数的期望值 这题不看题解好难想......(感谢zhx和zhx两位大佬的题解) len很小,考虑状压DP,显然我们要状压询问,要定义两个状态,f[]和num[] 1表示询问,0表示未询问 那么,我们定义f[s]表示询问状态s距离确定一个字符串所需要的期望值. 定义tot是s状态剩余的询问的次数,那么显

状压DP题集

[状压DP]Codeforces - 580D Kefa and Dishes (状压DP+记忆化搜索)(经典) 题目大意: 有$n ( n \leq18 )$个菜,现在要挑选$m$道菜,每个菜有一个满意度$a_i$,还有$k$个关系,每个关系为 $a b c$,表示$a$在$b$之前吃的话,就会额外增加$c$的满意度,现在要你输出最大的满意度. 解题分析:$n$的数据范围很小,很容易想到状压DP. #include <bits/stdc++.h> using namespace std; #

CodeForces 21D Traveling Graph 状压dp+欧拉回路

题目链接:点击打开链接 题意: 给定n个点m条边的无向图 求从1点开始经过每条边至少一次最后回到1点的最小路程 显然就是找一条路径可重复的欧拉回路 思路: 首先对于欧拉回路的结论是:所有点的度数都为偶数 因为所有边至少经过一次,那么可以把题意转换成加最少多少条边使得图满足以上结论 而加的边目的是为了把奇度数转成偶度数,先floyd一下得到任意点间加边的最小花费 dp[i]表示状态i下度数都为偶数的最小花费. 状压dp,把i状态下,所有未选择的点中挑2个奇度数的转移即可. #include <cs

Codeforces 580D-Kefa and Dishes(状压DP)

原题链接:http://codeforces.com/problemset/problem/580/D 题意:在n个数字中有顺序地选择m个数字,每个数字对应有个值ai,每取一个数字答案加上ai,并且存在k个关系:x y c,如果x恰好排在y的前面,那么答案再加上ci的值.输出最大值. 思路:状压dp.dp[i][j]中,i是已经选了若干个数的情况,j是最后一个被选取的数,i从选取1个到m个枚举下去,j从第1个数到第n个数进行枚举就能得到答案. AC代码: 1 #include<iostream>

CodeForces 757D Felicity&#39;s Big Secret Revealed(状压DP)

题意:给定一个01串,一个有效的n切割定义如下:一个横杠代表一次切割,第一条横杠前面的01串不算,最后一条横杠后面的01串不算,将两个横杠中的01串转化成十进制数字,假设这些数字的最大值是MAX且这些数字囊括了1-MAX的所有数字,则称为一次有效切割.求2~n+1次有效切割的切法. 思路: 由于题目要求包含所有1-MAXN的数字,且n<=75,所以MAXN<=20.另dp[i][j]表示第i位前面有一个横杆且存在j这个状态,接着从第i位开始枚举到第j位为下一个横杆的位置,设这两段横杆之间的数字