Codeforces 859D - Third Month Insanity

题意

\(2^n\) 个人要进行比赛,每次 \(2i\)\(2i+1\) 号人进行比赛(\(i\in [0,2^{n-1})\) )。这一轮中赢的人进入下一轮。下一轮比赛的时候把进入这一轮的人按编号排好,仍然是像之前那样相邻的进行一次比赛。最后只剩下一个人。

数据给出对于 \(x,y\)\(x\) 打赢 \(y\) 的概率。

\(i\) 轮比赛会角逐出 \(2^{n-i}\) 个赢家。我们要在比赛开始前,猜每轮的赢家(一轮的赢家一定要是上一轮的赢家)。第 \(i\) 轮每猜中一个赢家就会得到 \(2^{i-1}\) 的得分。

求最大的期望得分。

\(n\le 6\)

分析

只有猜到了与最终赢家相关的人才可能有得分。

轮数编号为 \([0,n)\)

\(f[i][x]\)\(x\) 在第 \(i\) 轮胜利,只统计与 \(x\) 有关的人(递归地定义,与 \(x\) 比赛过的人以及与他们有关的人)的猜测的得分。

这是容易转移的。设 \(o(i,x)\) 表示可能在第 \(i\) 轮与 \(x\) 比赛的人的集合,那么
\[ f[i][x]=f[i-1][x]+p[i][x]*2^i+\max _{v\in o(i,x)}f[i-1][v] \]
其中 \(p[i][x]\) 表示 \(x\) 在第 \(i\) 轮胜利的概率。 其实就是 \(x\) 一定要赢,看预测哪个对手得分比较高。

\(p[i][x]\) 也是容易得到的
\[ p[i][x]=p[i-1][x]*\sum _{v\in o(i,x)}p[i-1][v]*w[x][v] \]
\(w[x][v]\)\(x\) 打败 \(v\) 的概率。

代码

#include<bits/stdc++.h>
using namespace std;
inline char nchar() {
    static const int bufl=1<<20;
    static char buf[bufl],*a=NULL,*b=NULL;
    return a==b && (b=(a=buf)+fread(buf,1,bufl,stdin),a==b)?EOF:*a++;
}
inline int read() {
    int x=0,f=1;
    char c=nchar();
    for (;!isdigit(c);c=nchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=nchar()) x=x*10+c-'0';
    return x*f;
}
template<typename T> inline void Max(T &x,T y) {if (y>x) x=y;}
const int maxn=6;
const int maxs=1<<maxn;
double a[maxs][maxs],p[maxn][maxs],f[maxn][maxs];
int n,s,bin[maxs];
vector<int> o[maxs][maxn];
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    for (int i=2;i<maxs;++i) bin[i]=bin[i>>1]+1;
    n=read(),s=1<<n;
    for (int i=0;i<s;++i) for (int j=0;j<s;++j) {
        a[i][j]=read()/100.;
        if (i!=j) o[i][bin[i^j]].push_back(j);
    }
    for (int i=0;i<s;++i) f[0][i]=p[0][i]=a[i][o[i][0][0]];
    for (int i=1;i<n;++i) for (int j=0;j<s;++j) {
        double &r=p[i][j]=0;
        for (int x:o[j][i]) r+=p[i-1][x]*a[j][x];
        r*=p[i-1][j];
    }
    for (int i=1;i<n;++i) for (int j=0;j<s;++j) {
        double &r=f[i][j]=0;
        for (int x:o[j][i]) Max(r,f[i-1][x]);
        r+=f[i-1][j]+p[i][j]*(1<<i);
    }
    double ans=*max_element(f[n-1],f[n-1]+s);
    printf("%.12lf\n",ans);
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/7763165.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值