2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) K Tournament Wins
题目链接:http://codeforces.com/gym/101201
/* * @Author: lyucheng * @Date: 2017-10-22 14:38:52 * @Last Modified by: lyucheng * @Last Modified time: 2017-10-22 16:37:43 */ /* * 题意:2^k次方个人两两进行淘汰赛,排名高的人一定能胜过排名低的人,问你排名r的人的胜场期望 * * 思路:首先,如果r想赢i场的话那么一定要和2^i - 1个人在一个赛程二叉树中,所以r最多能赢的场次 * 就是(int)log2(2^k-r+1),也就是r和比他弱的人最大能组成的二叉树的深度,所以r能赢i场的概率 * 就是 C(2^k - r,2^i - 1) / C(2^k - 1, 2^i - 1)就是从比他弱的人里面选出2^i - 1个人数情况 * 除以从剩下的2^k - 1个人里选出 2^i - 1个人的情况,这只是前i场赢的概率,我们处理出来赢0~最 * 大场次的所有概率,就可以从最大场次向最低场次处理得出来所有准确能赢场数的概率,最后的期望 * 就是 ∑(准确能赢i场的概率(第i+1场一定输)*i * */ #include <bits/stdc++.h> #define MAXN (1<<20) using namespace std; int k,r; int n; double f[MAXN]; int tol; double cur[MAXN]; double need; double res; double cal(int n,int m){ return f[n]-f[m]; } inline void init(){ memset(f,0,sizeof f); for(int i=1;i<MAXN;i++) f[i]=f[i-1]+log(i); res=0; } int main(){ // freopen("in.txt","r",stdin); init(); scanf("%d%d",&k,&r); n=(1<<k); tol=(int)(log(n-r+1)/log(2)); for(int i=1;i<=tol;i++){ need=(1<<i); cur[i]=exp(cal(n-need,n-need-(r-1))-cal(n-1,n-r)); } double last=0; for(int i=tol;i>=1;i--){ res+=(cur[i]-last)*i; last+=(cur[i]-last); } printf("%.5f\n",res); }
我每天都在努力,只是想证明我是认真的活着.