题目描述
有两个队伍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多少分。答案保留到小数点后一位。
输入输出样例
输入样例#1:
2 3 7 1 5
输出样例#1:
20.0
首先暴力可以想到,两重循环枚举
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i]>b[j])
res+=(a[i]-b[j])*(a[i]-b[j]);
else
res-=(a[i]-b[j])*(a[i]-b[j]);
}
}
double ans=(double)((res*1.0)/(n*1.0));
printf("%.1lf",ans);
当然这是TLE,可以拿到30分
接下来很自然的谁想到前缀和优化,维护两个数组,Sum数组记录b数组的前缀和 Bin数组记录b的平方和的前缀和
经过一番简单的推导
#include<bits/stdc++.h>
#define N 50050
using namespace std;
long long n,a[N],b[N],Sum[N],Bin[N],oo=1,t;
int main() {
// freopen("mat.in","r",stdin);
// freopen("mat.out","w",stdout);
scanf("%lld",&n);
for(long long i=1; i<=n; i++)
scanf("%lld",&a[i]);
for(long long i=1; i<=n; i++)
scanf("%lld",&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+n+1);
Sum[0]=Bin[0]=0;
for(long long i=1; i<=n; i++) {
Sum[i]=Sum[i-1]+b[i];
Bin[i]=Bin[i-1]+b[i]*b[i];
}
for(long long i=1; i<=n; i++) {
while(b[oo]<=a[i]&&oo<=n)oo+=1;
t+=a[i]*a[i]*(oo-1-(n-(oo-1)));
t-=2*a[i]*(Sum[oo-1]-(Sum[n]-Sum[oo-1]));
t+=(Bin[oo-1]-(Bin[n]-Bin[oo-1]));//这三句是核心代码(其实很容易推)(完全平方公式)(a-b)^2=a^2-2*a*b+b^2
}
double ans=(double)((t*1.0)/(n*1.0));
printf("%.1lf\n",ans);
return 0;
}