题意: 有r场对局,2^r个人,你在当中实力排在第k位,当一个强的人跟弱的人打的时候,强的人赢的概率是p。你可以自由安排大家对局,最后留下来的人是胜者,问怎么安排对局你自己的胜率最高,最高是多少,输出。
思路: 我们很容易想到你只有多更比你弱的人打,你成为最终胜者的概率才会越高。所以最优的情况是你跟弱者打,强者内部打,弱者内部打。直到一方没有。但是有个问题就是当强者的人数时奇数时,你就需要判断两种情况,一种是强者赢了,一种是强者输了。最后我们按最优的方法打就行了。用dfs来递归。(记得加上记忆化搜索,没加会超时,亲身经历)
#include<bits/stdc++.h>
using namespace std;
#define double long double
typedef unsigned long long ll;
ll r,k;
double p;
map<pair<ll,ll>,double >mp;
double qpow(double a,int b)
{
double ans=1.0;
while(b!=0)
{
if(b&1){
ans*=a;
}
a=a*a;
b>>=1;
}
return ans;
}
double dfs(ll a,ll b)
{
if(mp.find({a,b})!=mp.end()){
return mp[{a,b}];
}
if(a==0){
int e=b;
b++;
int cnt=0;
for(int i=1;i<=64;i++){
b>>=1;
if(b==1){
cnt=i;
break;
}
}
mp[{a,e}]=qpow(p,cnt);
return mp[{a,e}];
}
if(b==0){
int e=a;
a++;
int cnt=0;
for(int i=1;i<=64;i++){
a>>=1;
if(a==1){
cnt=i;
break;
}
}
mp[{e,b}]=qpow(1.0-p,cnt);
return mp[{e,b}];
}
double maxx=1;
if(a%2==0){
double x=dfs(a>>1,(b>>1))*p;
mp[{a,b}]=x;
return x;
}else{
double x1=dfs((a>>1)+1,(b>>1)-1)*p*p;
double x2=dfs(a>>1,b>>1)*p*(1-p);
mp[{a,b}]=x1+x2;
return x1+x2;
}
}
int main()
{
ll t;
scanf("%lld",&t);
while(t--)
{
scanf("%lld%lld%Lf",&r,&k,&p);
ll a=k-1;
ll b=(1ll<<r)-k;
if(p<0.5){
swap(a,b);
p=1-p;
}
mp.clear();
mp[{0,1}]=p;
mp[{1,0}]=1.0-p;
double ans=dfs(a,b);
printf("%.6Lf\n",ans);
}
return 0;
}