題目描述
有兩個隊伍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多少分。答案保留到小數點後一位。
輸入輸出樣例
2 3 7 1 5
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;
}