• 2020-10-15 集训题目题解


    Game with Probability Problem

    题目传送门

    题目大意

    (n) 个石子在这里,Alice 和 Bob 轮流投掷硬币,如果正面朝上,则从 (n) 个石子中取出一个石子,否则不做任何事。取到最后一颗石子的人胜利。Alice 在投掷硬币时有 (p) 的概率投掷出他想投的一面,Bob 有 (q) 的概率投掷出他相投的一面。

    现在 Alice 先手投掷硬币,假设他们都想赢得游戏,问你 Alice 胜利的概率为多少。

    (nle 99999999,0.5le p,qle 0.99999999)

    思路

    怎么说呢?jb题吧。

    首先,我们考虑设 (f_{n,0/1}) 表示还剩 (n) 颗石子当前为 Alice or Bob 时 Alice 赢 的概率。

    然后我们发现如果 (f_{n-1,1}<f_{n-1,0}) ,那么两个人都不会翻正面,因为对于 Alice 而言我翻了正面,我赢的概率就变小了,而 Bob 如果翻了那么就会让 Alice 更优。

    于是我们可以得到 dp 式:

    [f_{n,0}=p imes f_{n,1}+(1-p) imes f_{n-1,1} ]

    [f_{n,1}=q imes f_{n,0}+(1-q) imes f_{n-1,0} ]

    然后解方程即可,这里就不赘述。

    接着,我们发现,如果 (f_{n-1,1}ge f_{n-1,0}),那么两个人都会翻正面,证明同上文,于是可以得到 dp 式:

    [f_{n,0}=p imes f_{n-1,1}+(1-p) imes f_{n,1} ]

    [f_{n,1}=q imes f_{n-1,0}+(1-q) imes f_{n,0} ]

    解法同上文。

    但是,到这一步我们只能做到 (Theta(Tn)),但是我们发现这个东西收敛速率是指数级的,于是我们每次跑到 (1000) 就好了。

    ( exttt{Code})

    int T;read (T);
    while (T --> 0){
    	int n;scanf ("%d%Lf%Lf",&n,&p,&q);
    	f[0][0] = 0,f[0][1] = 1,n = min (n,1000);
    	for (Int i = 1;i <= n;++ i){
    		double p1 = p,q1 = q;
    		if (f[i - 1][1] < f[i - 1][0]) p1 = 1 - p,q1 = 1 - q;
    		f[i][0] = (f[i - 1][1] * p1 + f[i - 1][0] * (1 - p1) * q1) / (1 - (1 - p1) * (1 - q1));
    		f[i][1] = (f[i - 1][0] * q1 + f[i - 1][1] * (1 - q1) * p1) / (1 - (1 - p1) * (1 - q1));
    	}
    	printf ("%.6Lf
    ",f[n][0]);
    }
    

    玩个球

    题目传送门

    题目大意

    有一个 (01) 序列,每次可以随机从当前序列中选出一个 (x),然后可以从 (x) 或者 (n-x+1) 中选一个((n) 是当前序列长度)删掉。执行 (k) 此操作。问最后 (1) 的最大期望值。

    一开始序列长度 (,kle 30)

    思路

    这个题目做出来不难,难的是证明时间复杂度。

    这个题目可以直接使用暴力状压,问题就是状态数到底最多有多少个。可以预料到,虽然最坏 (n imes 2^n),但是实际上远远达不到。

    考虑构造最坏情况。我们发现实际上我们就是构造一个序列使得它的不同子序列个数尽可能大,然后我们发现这个无非是 (1010101010...),我们经过验证发现,实际上状态数最多只有 (72821273)。足以通过此题。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 31
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int n,k;
    
    double dp[24][1 << 23];
    unordered_map <int,double> mp[MAXN];
    int tots = 0;
    double dfs (int siz,int nowS){
    	if (siz == n - k) return 0;tots ++; 
    	if (siz > 23 && mp[siz].find (nowS) != mp[siz].end()) return mp[siz][nowS];
    	if (siz <= 23 && dp[siz][nowS] != -1.0) return dp[siz][nowS];
    	double ans = 0;
    	for (Int i = 1;i <= siz / 2;++ i){
    		int con1 = nowS >> i - 1 & 1,con2 = nowS >> siz - i & 1;
    		int toS1 = nowS & ((1 << i - 1) - 1) | (nowS >> i << i - 1);
    		int toS2 = nowS & ((1 << siz - i) - 1) | (nowS >> siz - i + 1 << siz - i);
    		ans += 2 * max (dfs (siz - 1,toS1) + con1,dfs (siz - 1,toS2) + con2);
    	}
    	if (siz & 1){	
    		int ind = siz + 1 >> 1,con = nowS >> ind - 1 & 1;
    		int toS = nowS & ((1 << ind - 1) - 1) | (nowS >> ind << ind - 1);
    		ans += dfs (siz - 1,toS) + con;
    	}
    	ans /= siz;
    	if (siz <= 23) dp[siz][nowS] = ans;
    	else mp[siz][nowS] = ans;
    	return ans;
    }
    
    char s[MAXN];
    
    signed main(){
    	read (n,k),scanf ("%s",s + 1);int S = 0;
    	for (Int i = 1;i <= n;++ i) S |= (1 << i - 1) * (s[i] == 'W');
    	for (Int i = n - k + 1;i <= min (23,n);++ i) for (Int j = 0;j < (1 << i);++ j) dp[i][j] = -1.0;
    	printf ("%.6f
    ",dfs (n,S));
    	cout << tots << endl;//输出状态数 
    	return 0;
    }
    

    [JLOI2012]时间流逝

    题目传送门

    题目大意

    现在有阈值 (t) 以及 (n) 个值,有若干轮,每次有 (p) 的概率丢掉当前拥有的权值最小值,(1-p) 的概率获得一个比当前权值最小值还小的权值。当拥有的权值之和 (>t) 之后就会结束。问期望结束轮数。

    (nle 50),最多 (50) 组数据

    思路

    不难列出 dp 式,设 (f_{S}) 表示拥有权值状态为 (S) 时还需的期望轮数,假设 (S) 去掉最小权值为 (nxtS),可以得到转移式:

    [f_{S}=1+p imes f_{nxtS}+(1-p)/ ext{size}(min{S})sum_{val_xle min{S}} f_{Soplus x} ]

    我们发现这个式子明显可以用一个套路来转换,我们可以假设 (f_{S}) 都可以表示为 (k imes f_{nxtS}+b),那么可以将上式变为:

    [f_{S}=1+p imes f_{nxtS}+(1-p)/ ext{size}(min{S})sum_{val_xle min{S}} (k imes f_{S}+b) ]

    (并不保证 (k,b) 相同)

    (A=(1-p)/ ext{size}(min{S}))继续变化可以得到:

    [f_S imes (1-A imes (sum k))=p imes f_{nxtS}+A imes (sum b)+1 ]

    然后你发现我们就做完了。注意四舍五入的细节,具体见代码。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 55
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    struct Node{
    	double x,y;
    	Node(){}
    	Node (double _x,double _y){x = _x,y = _y;}
    	Node operator * (double p){return Node (x * p,y * p);}
    	Node operator + (const Node &p)const{return Node (x + p.x,y + p.y);}
    };
    
    void operator += (Node a,Node b){a = a + b;}
    void operator *= (Node a,double b){a = a * b;}
    
    double P;
    int T,N,val[MAXN];
    
    Node dfs (int Sum,int Minv){
    	if (Sum > T) return Node (0,0);
    	double k = 0,b = 0,p = !Sum ? 0 : P,A = (1.0 - p) / Minv;
    	for (Int i = 1;i <= Minv;++ i){
    		Node ano = dfs (Sum + val[i],i);
    		k += ano.x,b += ano.y;
    	}
    	return Node (p / (1 - A * k),(A * b + 1) / (1 - A * k));
    }
    
    signed main(){
    	while (~scanf ("%lf",&P)){
    		read (T,N);
    		for (Int i = 1;i <= N;++ i) read (val[i]);
    		sort (val + 1,val + N + 1),printf ("%0.3lf
    ",dfs (0,N).y);
    	}
    	return 0;
    }
    /*
    f[S]=p*f[nxtS]+(1-p)/siz[min{S}]sum_{x
    otin S} f[S|x]+1
    f[S]=p/(1-A(sum k))*f[nxtS]+(A(sum b)+1)/(1-Asum k)
    */
    
  • 相关阅读:
    STM32-M0中断优先级介绍
    source insight之quicker.em宏的使用
    LORA---关于LORA的30个常见问题解答
    【原创】Mac上编译Hadoop1.0.3出现的一些问题
    Mac中下载JDK手动更新出现“只支持10.7.3以上的系统版本”问题解决方案
    【Java基础】Java内部类
    【Java基础】Java类及成员和修饰符的关系
    【Java基础】Java接口的总结
    【Java基础】抽象类和抽象方法的总结
    【Java基础】Java中的多态
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13823482.html
Copyright © 2020-2023  润新知