题目大意
有 n n n个选手参加比赛,比赛有两道题。
对于第一题,第 i i i个选手有 50 % 50\% 50%的可能拿到 a i , 1 a_{i,1} ai,1分,有 50 % 50\% 50%的可能拿到 0 0 0分。
对于第二题,第 i i i个选手有 50 % 50\% 50%的可能拿到 a i , 2 a_{i,2} ai,2分,有 50 % 50\% 50%的可能拿到 0 0 0分。
一名选手的排名为分数比他高的选手的个数加1。求每个选手的期望排名。
题解
每个选手总共可能有4种成绩,每种成绩都为 1 4 \dfrac 14 41的概率。
先只考虑选手 a a a的一种成绩对选手 b b b的一种成绩的贡献。如果选手 a a a的一种成绩大于选手 b b b的一种成绩,那么在这种情况下 a a a对 b b b排名的贡献为1,而出现这种情况的概率为 1 16 \dfrac{1}{16} 161,所以这种情况对 b b b的期望排名的贡献为 1 16 \dfrac{1}{16} 161。
我们可以把每种选手的各种成绩放在一起排序。选手 i i i的期望排名就是,对于选手 i i i的各个成绩,在这个成绩之前的不是选手 i i i的成绩的成绩的数量之和乘 1 16 \dfrac{1}{16} 161,最后再加1。
因为 a a a的值比较小,所以可以用桶来维护。
时间复杂度为 O ( n + k ) O(n+k) O(n+k),其中 k k k为桶的大小。
code
#include<bits/stdc++.h>
using namespace std;
int n,ans,a[100005][2],z[200005];
double pt;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i][0],&a[i][1]);
++z[0];
++z[a[i][0]];
++z[a[i][1]];
++z[a[i][0]+a[i][1]];
}
for(int i=20000;i>=0;i--){
z[i]+=z[i+1];
}
for(int i=1;i<=n;i++){
ans=z[1]+z[a[i][0]+1]+z[a[i][1]+1]+z[a[i][0]+a[i][1]+1];
if(a[i][0]!=0) --ans;
if(a[i][1]!=0) --ans;
if(a[i][0]+a[i][1]!=0) --ans;
if(a[i][1]!=a[i][0]) --ans;
if(a[i][0]+a[i][1]!=a[i][0]) --ans;
if(a[i][0]+a[i][1]!=a[i][1]) --ans;
pt=1.0*ans/16+1;
printf("%.6f\n",pt);
}
return 0;
}