[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} 1−dpm,n−1。
- 询问一张后手的牌,后手会将这张牌舍弃掉,然后后手变成先手,此时原来先手的胜率为 1 − d p m − 1 , n 1-dp_{m-1,n} 1−dpm−1,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+(1−p)m+1m(1−dpm−1,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(1−dpm,n−1)+(1−p)(m+1m(1−dpm−1,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+(1−p)m+1m(1−dpm−1,n))=(1−q)(p(1−dpm,n−1)+(1−p)(m+1m(1−dpm−1,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+(1−p)m+1m(1−dpm−1,n)=p(1−dpm,n−1)+(1−p)(m+1m(1−dpm−1,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(1−p)=w2,1p+w2,2(1−p)可以得到
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,2−w1,1−w2,2w1,2−w2,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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
2021-01-09 [SDOI2014]数表