比赛 解题报告
比赛
题目描述
有两个队伍A和B,每个队伍都有n个人。这两支队伍之间进行n场1对1比赛,每一场都是由A中的一个选手与B中的一个选手对抗。同一个人不会参加多场比赛,每个人的对手都是随机而等概率的。例如A队有A1和A2两个人,B队有B1和B2两个人,那么(A1 vs B1,A2 vs B2)和(A1 vs B2,A2 vs B1)的概率都是均等的50%。
每个选手都有一个非负的实力值。如果实力值为X和Y的选手对抗,那么实力值较强的选手所在的队伍将会获得(X-Y)^2的得分。
求A的得分减B的得分的期望值。
输入输出格式
输入格式:
第一行一个数n表示两队的人数为n。 第二行n个整数,第i个数A[i]表示队伍A的第i个人的实力值。 第三行n个整数,第i个数B[i]表示队伍B的第i个人的实力值。
输出格式:
输出仅包含一个实数表示A期望赢B多少分。答案保留到小数点后一位(注意精度)。
说明
对于30%的数据,n≤50。
对于100%的数据,n≤50000;A[i],B[i]≤50000。
昨天刚学期望今天就考了,喵喵喵
如果把\(b\)队看成位置,把\(a\)队的人往里面放,一共可以产生\(n!\)种情况。
则对任意的二元配对组\(A_i\)与\(B_j\),它们产生的答案即为
\((A_i-B_i)*(n-1)!/n!\),乘上的\((n-1)!\)即为它的出现次数
则总答案为
\((\sum_{i=1}^{n} \sum_{j=1,A[i]>=B[j]}^{n} {(A[i]-B[j])}^2-\sum_{i=1}^{n} \sum_{j=1,A[i]<B[j]}^{n} {(A[i]-B[j])}^2)/n\)
将A,B两个数组排序,递推统计即可。把完全平方公式拆开多维护一点信息即可。
注意精度问题,此题输入全为整数,所以最后再转double
#include <cstdio>
#include <algorithm>
#include <cmath>
#define ld long long
const int N=50010;
int n,pos=0;
ld a[N],b[N],s1=0,s2=0,ans=0,sum1=0,sum2=0;
void init()
{
std::sort(a+1,a+1+n);
std::sort(b+1,b+1+n);
while(pos<n&&a[1]>=b[pos+1]) pos++;
for(int i=1;i<=pos;i++)
{
s1+=(a[1]-b[i])*(a[1]-b[i]);
sum1+=b[i];
}
for(int i=n;i>pos;i--)
{
s2+=(b[i]-a[1])*(b[i]-a[1]);
sum2+=b[i];
}
ans+=s1-s2;
}
void work()
{
for(int i=2;i<=n;i++)
{
int las=pos+1;
while(pos<n&&a[i]>=b[pos+1])
pos++;
for(int j=las;j<=pos;j++)
sum2-=b[j];
for(int j=las;j<=pos;j++)
{
s1+=(a[i]-b[j])*(a[i]-b[j]);
s2-=(b[j]-a[i-1])*(b[j]-a[i-1]);
}
s1+=(a[i]-a[i-1])*((las-1)*(a[i]+a[i-1])-2*sum1);
s2+=(a[i]-a[i-1])*((n-pos)*(a[i]+a[i-1])-2*sum2);
ans+=s1-s2;
for(int j=las;j<=pos;j++)
sum1+=b[j];
}
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("zj.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lld",a+i);
for(int i=1;i<=n;i++)
scanf("%lld",b+i);
init();
work();
double out=double(ans)/double(n);
printf("%.1lf\n",out);
return 0;
}
2018.6.26