SP4060 KPGAME - A game with probability
题目链接:SP4060
Alice和Bob在玩一个游戏。
有n个石子在这里,Alice和Bob轮流投掷硬币,如果正面朝上,则从n个石子中取出一个石子,否则不做任何事。取到最后一颗石子的人胜利。Alice在投掷硬币时有p的概率投掷出他想投的一面,Bob有q的概率投掷出他相投的一面。
现在Alice先手投掷硬币,假设他们都想赢得游戏,问你Alice胜利的概率为多少。
Tleq 50, nleq 10^8, 0.5leq p,q < 1
Tutorial
不妨设 dp[i][0/1] 表示目前是 Alice/Bob 投掷硬币,还剩 i 个石子,Alice 胜利的概率。
显然有 dp[0][0]=1, dp[0][1]=0。转移的话需要分两类情况讨论:
若 dp[i-1][0] > dp[i-1][1]i-1 个石子时,若轮到 Alice 投掷硬币,Alice 获胜的概率更大,因此 Alice 因想尽办法尽可能在剩余第 i 个石子时,投掷反面,让 Bob 拿走第 i 颗石子。Bob 为了让 Alice 尽可能输,因此他希望在剩余 i 个石子时,他能够投掷反面,让 Alice 拿走第 i 颗石子。
同理,若 dp[i-1][0] < dp[i-1][1]i 颗石子。
因此,我们可以列出转移方程。
其中,p,q 在 dp[i-1][0] < dp[i-1][1]A,B,否则为 1-A,1-B。
注意到当 i 增大的同时,dp 数组的值会不断减小,因此之后可以忽略不记,所以可以将 n 与 1000 取 min 即可通过本题。
当然,如果你感觉比较好,会发现 p,q 的取值与 i 的奇偶性有关,因此可以两步一起跑,矩阵快速幂加速转移即可。
复杂度 O(TNlog N)。
Solution
代码语言:javascript复制#include<bits/stdc .h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define W while
#define I inline
#define RI register int
#define LL long long
#define Cn const
#define CI Cn int&
#define gc getchar
#define D isdigit(c=gc())
#define pc(c) putchar((c))
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;
namespace Debug{
Tp I void _debug(Cn char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts I void _debug(Cn char* f,Ty x,Ar... y){W(*f!=',') cerr<<*f ;cerr<<'='<<x<<",";_debug(f 1,y...);}
Tp ostream& operator<<(ostream& os,Cn vector<Ty>& V){os<<"[";for(Cn auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug(#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
namespace FastIO{
Tp I void read(Ty& x){char c;int f=1;x=0;W(!D) f=c^'-'?1:-1;W(x=(x<<3) (x<<1) (c&15),D);x*=f;}
Ts I void read(Ty& x,Ar&... y){read(x),read(y...);}
Tp I void write(Ty x){x<0&&(pc('-'),x=-x,0),x<10?(pc(x '0'),0):(write(x/10),pc(x '0'),0);}
Tp I void writeln(Cn Ty& x){write(x),pc('n');}
}using namespace FastIO;
Cn int N=1e6 10;
int Tt,n;double A,B,f[N][2],p,q;
int main(){
RI i;read(Tt);W(Tt--){
for(read(n),scanf("%lf%lf",&A,&B),assert(0.5<=A&&A<=1&&0.5<=B&&B<=1),f[0][0]=0,f[0][1]=1,i=1;i<=min(n,1000);i )
f[i-1][1]>f[i-1][0]?(p=A,q=B):(p=1-A,q=1-B),f[i][0]=(f[i-1][0]*q*(1-p) f[i-1][1]*p)/(1-(1-q)*(1-p)),f[i][1]=f[i][0]*(1-q) f[i-1][0]*q;
printf("%.6lfn",f[min(n,1000)][0]);
}return 0;
}