【未知来源】记忆

题意

  朋友首先给你看了n个长度相同的串,然后从中等概率随机选择了一个串。
  每一轮你可以询问一个位置上的正确字符,如果能够凭借已有的信息确定出朋友所选的串,那么游戏就结束了,你的成绩就是所用的轮数。
  由于你实在太笨,不会任何策略,因此你采用一种方法,每次等概率随机询问一个未询问过的位置的字符。
  现在你想知道,在这种情况下,你猜出结果所需的期望次数。
  \(n\le 50,\space l\le 20\)

题解

  起手写了个算错复杂度的 \(O(n!\times n^3)\) 暴力

  暴力 \(\text{dp}\) 很显然:因为除了最后一个询问点以外,之前的询问点无论按什么顺序访问,询问次数都是一样的,所以设 \(f(i,j)\) 表示答案串是第 \(i\) 个时,已经询问的点集为二进制数 \(j\),期望还需要询问多少次才能猜出答案。倒推,从每个非终止状态向前驱暴力转移(终止状态就是询问点集 \(j\) 后能确定答案是第 \(i\) 个串),最终答案是 \(\frac{\sum\limits_{i=1}^n f(i,0)}{n}\)。复杂度 \(O(2^l n^2)\),能(卡)过 \(60\) 分(为什么大家都觉得 \(1s\) 随便跑 \(4e8\) 鸭)

  正解思路比较巧妙(然而 zjr 说是个套路)。
  我们有一个 \(O(n^2 l)\) 的方法预处理 \(g(i)\),表示询问点集 \(i\) 后不能确定的字符串集合(用一个 \(n\) 位二进制数表示)。
  然后设 \(f(i)\) 表示询问点集 \(i\) 后,对于 \(n\) 种答案串的情况 期望还需要询问的次数之和。
  类似于暴力倒推,把状态看成一个 \(\text{DAG}\),一个状态(点集)有很多个后继状态,状态 \(i\)\(f(i)\) 即为所有后继状态 \(j\)\(f(j)\) 的平均数 加上询问状态(点集)\(i\) 不能确定的字符串集合(感性理解就是,对于每个不确定的字符串为答案的情况,都需要询问一次才能到达后继状态,有 \(k\) 个不确定的字符串询问次数就加 \(k\))。
  最终答案是 \(\frac{f(0)}{n}\)。复杂度 \(O(2^l n)\)
  (zjr 是神仙,不接受反驳)

#include<bits/stdc++.h>
#define ll long long
#define N 51
#define L 21
const int lim = (1<<20) - 1;
using namespace std;
inline int read(){
	int x=0; bool f=1; char c=getchar();
	for(;!isdigit(c); c=getchar()) if(c=='-') f=0;
	for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
	if(f) return x; return 0-x;
}
int n,len,bcnt[lim+5];
double f[1<<L]; ll g[1<<L];
char s[N][L];
inline int calc(ll x){
	int res=bcnt[x&lim];
	res+=bcnt[(x>>=20)&lim];
	res+=bcnt[(x>>=20)&lim];
	return res;
}
int main(){
	n=read();
	for(int i=1; i<=lim; ++i) bcnt[i]=bcnt[i>>1]+(i&1);
	for(int i=0; i<n; ++i) scanf("%s",s[i]);
	len=strlen(s[1]);
	for(int i=0; i<n; ++i)
		for(int j=0; j<n; ++j) if(i!=j){
			int tmp=0; 
			for(int k=0; k<len; ++k)
				if(s[i][k]==s[j][k]) tmp|=(1<<k);
			g[tmp]|=(1ll<<i), g[tmp]|=(1ll<<j);
		}
	for(int i=(1<<len)-1; i>=0; --i){
		int cnt=0;
		for(int j=0; j<len; ++j) if(!(i&(1<<j)))
			f[i]+=f[i|(1<<j)], g[i]|=g[i|(1<<j)], ++cnt;
		if(cnt) f[i]/=cnt;
		f[i]+=calc(g[i]);
	}
	printf("%.10lf\n",f[0]/n);
	return 0;
}
posted @ 2019-08-23 17:05  大本营  阅读(176)  评论(0)    收藏  举报