比賽4.11

題目描述

有兩個隊伍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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章