【题解】NOIp模拟:比赛

比赛
Description
有两个队伍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的得分的期望值。

Input
第一行一个数n表示两队的人数为n。
第二行n个整数,第i个数A[i]表示队伍A的第i个人的实力值。
第三行n个整数,第i个数B[i]表示队伍B的第i个人的实力值。

Output
输出仅包含一个实数表示A期望赢B多少分。答案保留到小数点后一位(注意精度)。

Sample Input
2
3 7
1 5

Sample Output
20.0

Hint
【数据规模】
对于30%的数据,n≤50。
对于100%的.据,n≤50000;A[i],B[i]≤50000。

首先考虑 O ( n 2 ) O(n^2) 暴力
a i , b j a_i,b_j 拎出来,让他们两个人打,他们两个人会打 ( n 1 ) ! (n-1)!
然后总方案数是 n ! n! ,所以答案是 i = 1 n j = i + 1 n ( a i b j ) 2 n \frac{\sum_{i=1}^{n}\sum_{j=i+1}^{n}(a_i-b_j)^2}{n}
把式子拆开来, ( a i b j ) 2 = a i 2 + b j 2 2 a i b j (a_i-b_j)^2=a_i^2+b_j^2-2a_ib_j
直接把 a a 排序,对于每个 b b ,二分在 a a 数组里面找到位置,对于 a a 维护它的前缀和,前缀平方和就好了

Code:

#include <bits/stdc++.h>
#define maxn 50010	
#define LL long long
using namespace std;
LL a[maxn], n, sum[maxn], sum2[maxn];

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

int find(LL x){
	int l = 1, r = n, ans = 0;
	while (l <= r){
		int mid = (l + r) >> 1;
		if (a[mid] <= x) ans = mid, l = mid + 1; else r = mid - 1;
	}
	return ans;
}

int main(){
	freopen("mat.in", "r", stdin);
	freopen("mat.out", "w", stdout);
	n = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	double ans = 0;
	sort(a + 1, a + 1 + n);
	for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i], sum2[i] = sum2[i - 1] + a[i] * a[i];
	for (int i = 1; i <= n; ++i){
		LL x = read();
		if (x <= a[1]) ans += 1LL * n * x * x + sum2[n] - 2LL * x * sum[n];
		else if (x >= a[n]) ans -= 1LL * n * x * x + sum2[n] - 2LL * x * sum[n];
		else{
			LL s = find(x);
			ans += -(s * x * x + sum2[s] - 2LL * x * sum[s]) + 1LL * (n - s) * x * x + sum2[n] - sum2[s] - 2LL * x * (sum[n] - sum[s]);
		}
	}
/*	for (int i = 1; i <= n; ++i){
		LL x = read();
		for (int i = 1; i <= n; ++i)
			if (x <= a[i]) ans += (a[i] - x) * (a[i] - x);
			else ans -= (x - a[i]) * (x - a[i]);
	}*/
	printf("%.1lf\n", 1.0 * ans / n);
	return 0; 
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/108238035