题意

你和你的朋友玩一个游戏,游戏规则如下。

你的朋友创造 n 个长度均为 m 的不相同的字符串,然后他随机地选择其中一个。他选择这些字符串的概率是相等的,也就是说,他选择 n 个字符串中的每一个的概率是 1/n 。你想猜猜你的朋友选择了哪个字符串。

为了猜到你的朋友选择了哪个字符串,你可以问他问题,形式如下:字符串中第 pos 个字符是什么?当问题的答案为唯一标识字符串时,我们认为这个字符串是猜测的。在字符串被猜测后,你将停止提问。

你没有一个特殊的策略,所以你每次可能会等概率的问任何一个你从没提过的位置。你的任务是确定你猜到你的朋友选的字符串所需次数的期望。

输入格式

第一行包括一个数字 n 。接下来 n 行,每行一个字符串,表示你朋友创造出的字符串。除此之外,所有字符的长度是相同的,在1~20之间。

输出格式

输出期望。答案保留九位小数。误差在\(10^-9\)以内.

输入输出样例

输入样例#1:

2

aab

aac

输出样例#1:

2.000000000000000

输入样例#2:

3

aaA

aBa

Caa

输出样例#2:

1.666666666666667

输入样例#3:

3

aca

vac

wqq

输出样例#3:

1.000000000000000


搞了一上午

撞鸭 + 期望

我们预处理出unf[i]表示在状态为i的情况下有哪些串是符合的

unf[i]我们可以通过枚举两个串来计算他们相同的位置

然后我们再从大到小更新unf

我们还可以求出来Num[i]表示在状态为i的情况下有多少串是符合的

f[i] 表示状态为i时距离确定的期望

然后就可以从后向前转移了

状态转移方程\(f[i] = \sum_{j = 1 \&\& (! i | (1 << (j - 1)))}^{n}{\frac{f[i]|1<<(j-1)]}{tot} * \frac{Num[i]|1<<(j-1)}{Num[i]}} + 1\)

tot表示的是状态i中还有多少个位置没问

解释下\(\frac{Num[i||1<<(j-1)}{Num[i]}\)的意思

设\(j = i | (1 << (j - 1)\)

num[j] 一定不大于 num[i]

因为是j向i转移不好考虑

换成i向j转移思考,i有num[j]种选择可以变成j的样子

但是有(num[i]-num[j])的选择是可以直接分辨出答案来的

所以由j向i转移的时候就只需要考虑到那num[j]种情况,所以只有\(num[j]/num[i]\)的概率可以继续转移

余下的\((num[i]-num[j])/num[j]\)就是已经确定的那些

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
# define int long long
const int M = 55 ;
const int N = (1 << 20) + 5 ;
using namespace std ;
int m , n ;
char s[M][M] ;
int unf[N] , Num[N] ;
double f[N] ;
# undef int
int main() {
# define int long long
scanf("%lld",&m) ;
for(int i = 1 ; i <= m ; i ++) scanf("%s",s[i] + 1) ;
n = strlen(s[1] + 1) ;
for(int i = 1 ; i <= m ; i ++)
for(int j = i + 1 , sit ; j <= m ; j ++) {
sit = 0 ;
for(int k = 1 ; k <= n ; k ++)
if(s[i][k] == s[j][k])
sit |= (1LL << (k - 1)) ;
unf[sit] |= (1LL << (i - 1)) ;
unf[sit] |= (1LL << (j - 1)) ;
}
for(int i = (1 << n) - 1 ; i >= 1 ; i --)
for(int j = 1 ; j <= n ; j ++)
if(i & (1 << (j - 1)))
unf[i ^ (1 << (j - 1))] |= unf[i] ;
for(int i = 0 ; i < (1 << n) ; i ++)
for(int j = 1 ; j <= m ; j ++)
if(unf[i] & (1LL << (j - 1)))
Num[i] ++ ;
for(int i = (1 << n) - 2 , tot ; i >= 0 ; i --) {
if(!Num[i]) continue ;
tot = n ;
for(int j = 1 ; j <= n ; j ++)
if(i & (1 << (j - 1))) --tot ;
for(int j = 1 ; j <= n ; j ++) {
if(i & (1 << (j - 1))) continue ;
f[i] += f[i | (1 << (j - 1))] / (double)tot * ((double)Num[i | (1 << (j - 1))] / (double)Num[i]) ;
}
f[i] += 1.0 ;
}
printf("%.10lf\n",f[0]) ;
return 0 ;
}

CF482C Game with Strings的更多相关文章

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

    题目大意:甲和乙玩游戏,甲给出n(n<=50)个等长的字符串(len<=20),然后甲选出其中一个字符串,乙随机询问该字符串某一位的字符(不会重复询问一个位置),求乙能确定该串是哪个字符串 ...

  2. Hacker Rank: Two Strings - thinking in C# 15+ ways

    March 18, 2016 Problem statement: https://www.hackerrank.com/challenges/two-strings/submissions/code ...

  3. StackOverFlow排错翻译 - Python字符串替换: How do I replace everything between two strings without replacing the strings?

    StackOverFlow排错翻译 - Python字符串替换: How do I replace everything between two strings without replacing t ...

  4. Multiply Strings

    Given two numbers represented as strings, return multiplication of the numbers as a string. Note: Th ...

  5. [LeetCode] Add Strings 字符串相加

    Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2. ...

  6. [LeetCode] Encode and Decode Strings 加码解码字符串

    Design an algorithm to encode a list of strings to a string. The encoded string is then sent over th ...

  7. [LeetCode] Group Shifted Strings 群组偏移字符串

    Given a string, we can "shift" each of its letter to its successive letter, for example: & ...

  8. [LeetCode] Isomorphic Strings 同构字符串

    Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if the chara ...

  9. [LeetCode] Multiply Strings 字符串相乘

    Given two numbers represented as strings, return multiplication of the numbers as a string. Note: Th ...

随机推荐

  1. [K/3Cloud] 分录行复制和新增行的冲突如何处理

    新增行:执行AfterCreateNewEntryRow,这个函数里面对一些数据进行处理(比如字段给上默认值): 复制行:复制行过程中希望这些字段能够得到我修改行信息后的数据,如果不处理,执行到Aft ...

  2. 选学霸(codevs 3372)

    题目描述 Description 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议.所以老师想请你帮他求出他该选多少学霸,才能既不让同 ...

  3. poj_2506_Tiling_201407211555

    Tiling Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7509   Accepted: 3672 Descriptio ...

  4. UVA 140_Bandwidth

    题意: 定义一个结点的带宽是其距离所有相连结点的最远距离,一个图的带宽是图中所有结点带宽的最小值.给出一个图中各个结点的相邻情况,要求写出一个结点的排列,使得其所构成的图带宽最小. 分析: 枚举全排列 ...

  5. spring依赖注入中获取JavaBean

    一.这个接口有什么用? 当一个类实现了这个接口(ApplicationContextAware)之后,这个类就可以方便获得ApplicationContext中的所有bean.换句话说,就是这个类可以 ...

  6. 程序猿Web面试之JSON

     JSON是什么? JSON(JavaScript对象表示法), 是在网络通信下.经常使用的一种数据表达格式,它有助于我们于一个自描写叙述的,独立的和轻的方式呈现并交换数据. 这些数据能够易于和转 ...

  7. AutoCAD如何设置线宽

    一般要求粗实线粗实线0.4,细实线0.2mm. 1 先打开图层特性管理器,新建一个图层,专门放粗实线(我起名叫"我的粗实线",颜色设置为紫色,线宽为0.4mm),此前的乱七八糟的图 ...

  8. SQL Server游标 C# DataTable.Select() 筛选数据 什么是SQL游标? SQL Server数据类型转换方法 LinQ是什么? SQL Server 分页方法汇总

    SQL Server游标   转载自:http://www.cnblogs.com/knowledgesea/p/3699851.html. 什么是游标 结果集,结果集就是select查询之后返回的所 ...

  9. SUSE Linux源代码编译安装MySQL 5.6

    这篇文章主要介绍了SUSE Linux下源代码编译方式安装MySQL 5.6过程分享,本文使用SUSE Linux Enterprise Server 10 SP3 (x86_64)系统,须要的朋友能 ...

  10. android不是内部或外部命令,也不是可执行的程序或批处理文件

    问题: 原因:没有配置好android sdk环境变量 解决方法: (1)切换到android sdk下的tools文件夹,再执行android命令就可以启动Android SDK管理器,我的andr ...