比赛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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值