[CF98E]Help Shrek and Donkey

Help Shrek and Donkey

题解

这又是什么鬼畜博弈游戏。

我们先记 d p i , j dp_{i,j} dpi,j表示先手有 i i i张牌,后手有 j j j张牌的时先手的胜率。
此时先手直接猜牌时,获胜的概率为 1 m + 1 \frac{1}{m+1} m+11
此时先手提出询问,则会有三种情况,

  • 询问一张自己有的牌,这种时候就是在迷惑后手,让后手以为这张可能是正确的牌,如果后手信了的话,那么先手就必胜;否则就相当于舍弃掉了这张牌,因为到下一个先手的回合先手不能因此去获胜,所以后手肯定可以知道先手有这张牌,而后手变成先手,于是胜率就别成了 1 − d p m , n − 1 1-dp_{m,n-1} 1dpm,n1
  • 询问一张后手的牌,后手会将这张牌舍弃掉,然后后手变成先手,此时原来先手的胜率为 1 − d p m − 1 , n 1-dp_{m-1,n} 1dpm1,n
  • 询问正确的牌,此时后手如果认为先手没有诈自己,那么后手必胜;否则先手下回合就可以猜这张牌,先手必胜。

显然先手是没办法主观上区别情况2与情况3,所以当先手不选择情况1时,就有 m m + 1 \frac{m}{m+1} m+1m的概率进入情况2与 1 m + 1 \frac{1}{m+1} m+11的概率进入情况3,我们设先手有 p p p的概率选择情况1。
而对于后手,他是没办法主观上区分情况1与情况3的,所以他此时选择相信先手与不相信先手的概率应该是固定的,我们设后手有 q q q的概率相信先手。
当后手选择相信先手时,先手的胜率是 p + ( 1 − p ) m m + 1 ( 1 − d p m − 1 , n ) p+(1-p)\frac{m}{m+1}(1-dp_{m-1,n}) p+(1p)m+1m(1dpm1,n)
当后手选择不信先手时,先手的胜率是 p ( 1 − d p m , n − 1 ) + ( 1 − p ) ( m m + 1 ( 1 − d p m − 1 , n ) + 1 ) p(1-dp_{m,n-1})+(1-p)(\frac{m}{m+1}(1-dp_{m-1,n})+1) p(1dpm,n1)+(1p)(m+1m(1dpm1,n)+1)
由于后手不知道先手时怎么选择的,但后手 绝顶聪明,他可以算出先手的 p p p,所以后手绝对会去平衡这两个概率,使得这两个的代权加和最小。
q ( p + ( 1 − p ) m m + 1 ( 1 − d p m − 1 , n ) ) = ( 1 − q ) ( p ( 1 − d p m , n − 1 ) + ( 1 − p ) ( m m + 1 ( 1 − d p m − 1 , n ) + 1 ) ) q(p+(1-p)\frac{m}{m+1}(1-dp_{m-1,n}))=(1-q)(p(1-dp_{m,n-1})+(1-p)(\frac{m}{m+1}(1-dp_{m-1,n})+1)) q(p+(1p)m+1m(1dpm1,n))=(1q)(p(1dpm,n1)+(1p)(m+1m(1dpm1,n)+1))容易观察到,经过后手的平衡,先手的胜率肯定是趋近于两种情况中较小的一个的。
但我们的先手也是绝顶聪明的呀,他肯定不会让后手去决定他的概率,所以他肯定会先通过 p p p使得自己的两个概率都是一样的,免得后手选择较小的一个。
显然,这两边是一加一减的,如果两边都同增同减了,那么先手就别玩了,所以平衡后,所以通过先手的平衡,较小的一个肯定提高了,显然最好的情况是两个概率一样,这时候可以使得较小的概率最大。
也就是说,有
p + ( 1 − p ) m m + 1 ( 1 − d p m − 1 , n ) = p ( 1 − d p m , n − 1 ) + ( 1 − p ) ( m m + 1 ( 1 − d p m − 1 , n ) + 1 ) p+(1-p)\frac{m}{m+1}(1-dp_{m-1,n})=p(1-dp_{m,n-1})+(1-p)(\frac{m}{m+1}(1-dp_{m-1,n})+1) p+(1p)m+1m(1dpm1,n)=p(1dpm,n1)+(1p)(m+1m(1dpm1,n)+1)存在。
但这个表达式也太烦琐了,我们先将它换一下。
w 1 , 1 p + w 1 , 2 ( 1 − p ) = w 2 , 1 p + w 2 , 2 ( 1 − p ) w_{1,1}p+w_{1,2}(1-p)=w_{2,1}p+w_{2,2}(1-p) w1,1p+w1,2(1p)=w2,1p+w2,2(1p)可以得到 p = w 1 , 2 − w 2 , 2 w 2 , 1 + w 1 , 2 − w 1 , 1 − w 2 , 2 p=\frac{w_{1,2}-w_{2,2}}{w_{2,1}+w_{1,2}-w_{1,1}-w_{2,2}} p=w2,1+w1,2w1,1w2,2w1,2w2,2,这样就算出了我们先手的 p p p
有了 p p p,我们当然就可以求出我们的 d p n , m dp_{n,m} dpn,m了,从这两个中随便选一个算就可以,反正两个值都是一样的。
之后不过是不断地 d p dp dp下去,整个问题就都能够通过 d p dp dp解决,可以通过记忆化搜索实现。

时间复杂度 O ( n m ) O\left(nm\right) O(nm)
实际上该问题是一种典型的纳什博弈,也就是进行选择后两种概率是一样的。

源码

代码事实上很短。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;
typedef pair<int,int> pii;
const LL INF=0x7f7f7f7f7f7f7f7f;
const int mo=1e9+7;
const int inv2=5e8+4;
const int jzm=23333;
const int zero=20000;
const int lim=1000000;
const int orG=3,ivG=334845270;
const double Pi=acos(-1.0);
const double eps=1e-12;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,m;bool vis[MAXN][MAXN];
double dp[MAXN][MAXN];
double DP(int x,int y){
	if(!x)return 1.0/(y+1);if(!y)return 1;
	if(vis[x][y])return dp[x][y];vis[x][y]=1;
	double w11=1.0*y/(y+1)*(1.0-DP(y-1,x))+1.0/(y+1),w22=1.0;
	double w12=1.0-DP(y,x-1),w21=1.0*y/(y+1)*(1.0-DP(y-1,x));
	double P=(w12-w22)/(w21+w12-w11-w22);
	return dp[x][y]=P*w11+(1.0-P)*w12;
}
signed main(){
	read(n);read(m);
	printf("%.9f %.9f\n",DP(n,m),1.0-DP(n,m));
	return 0;  
}

谢谢!!!

posted @   StaroForgin  阅读(1)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
历史上的今天:
2021-01-09 [SDOI2014]数表
点击右上角即可分享
微信分享提示