zoukankan      html  css  js  c++  java
  • 【未知来源】记忆

    题意

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

    题解

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

      暴力 ( ext{dp}) 很显然:因为除了最后一个询问点以外,之前的询问点无论按什么顺序访问,询问次数都是一样的,所以设 (f(i,j)) 表示答案串是第 (i) 个时,已经询问的点集为二进制数 (j),期望还需要询问多少次才能猜出答案。倒推,从每个非终止状态向前驱暴力转移(终止状态就是询问点集 (j) 后能确定答案是第 (i) 个串),最终答案是 (frac{sumlimits_{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) 种答案串的情况 期望还需要询问的次数之和。
      类似于暴力倒推,把状态看成一个 ( ext{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
    ",f[0]/n);
    	return 0;
    }
    
  • 相关阅读:
    07四则运算三
    第一阶段冲刺01
    构建之法——阅读笔记01
    四则运算
    Windows32位或64位下载安装配置Scala
    Windows32或64位下载安装配置Spark
    在Hadoop中ResourceManager是干什么的?
    什么是NameNode和DataNode?他们是如何协同工作的?
    Hadoop1和Hadoop2的区别是什么?
    什么是yarn?
  • 原文地址:https://www.cnblogs.com/scx2015noip-as-php/p/11401247.html
Copyright © 2011-2022 走看看