3436 Help Shrek and Donkey
有n+m+1张牌,牌上的数字互不相同且均在[1,n+m+1]中。A有n张牌,B有m张牌,还有一张牌盖在桌上。现在A和B轮流操作,他们两个人都足够聪明,A先进行操作,当前操作的那一方有两种操作:
1. 猜盖在桌上的牌是什么,若猜对则直接获胜,猜错则直接输。
2. 猜一张对方的手牌,若猜对则对方需要把该牌扔掉,猜错则没有影响。
假设双方都绝顶聪明,问先手获胜的概率是多少。
n,m≤1000
输入
一行两个整数m,n(0≤m,n≤1000)
输出
一行两个整数表示A和B的胜率,保留到两位整数
输入样例
输入样例1:
0 3
输入样例2:
1 0
输出样例
输出样例1:
0.25 0.75
输出样例2:
1.00 0.00
解析:
这题难就难在先手有“欺骗”操作,也就是说,先手可以选择猜一张我手中的手牌,若后手认为先手在“欺骗”,则先手会丢失一张手牌;反之后手则会认为这张牌就是盖在桌上的那张,然后直接G。
首先注意到若无法确定桌上的牌,则先手必然不会去猜桌上的牌。
如果我们把猜对方的手牌称为“指定”,那么这时先手就只剩下两种操作,分别是“欺骗”和“指定”。后手也存在两种决策,分别是相信和不相信。
若先手选择“欺骗”,后手选择“相信”,收益为1;
若先手选择“欺骗”,后手选择“不相信”,收益为;
若先手选择“指定”,后手选择“相信”,收益为
若先手选择“指定”,后手选择“不相信”,收益为
我们设先手选择“指定”的概率为p
那么后手选择“相信”时先手获胜概率为
同理后手选择“不相信”时先手获胜的概率为
由于后手需要让先手获胜的概率尽量小,所以先手获胜的概率就是两者之中的较小值。而先手又要选择一个p好让自己获胜的概率尽量大。
注意到这是两条直线,且一条斜率大于0另一条斜率小于0,那么显然二者的交点即为答案。
时间复杂度。
放代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
cs int N=1e3+7;
bool vis[N][N];
double f[N][N];
inline double dp(int n,int m){
if(vis[n][m])return f[n][m];
vis[n][m]=true;
if(n==0)return f[0][m]=1./(m+1.);
if(m==0)return f[n][0]=1;
double t1=dp(m,n-1),t2=dp(m-1,n);
double p=t1/(t1+1./(m+1));
return f[n][m]=p*m/(m+1)*(1-t2)+1-p;
}
signed main(){
int n,m;
scanf("%d%d",&n,&m);dp(n,m);
printf("%.2f %.2f",f[n][m],1-f[n][m]);
return 0;
}