BSOJ 4852:比赛 暴力优化

29 篇文章 0 订阅
11 篇文章 0 订阅
4852 -- 【模拟试题】比赛
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。

其实题目对于这个所谓的期望的求法已经说得很清楚了,就是算两个队各个队员的差值乘以概率累加,这样说得很抽象,举个例子。
A队:A B C 
B队:a  b c 
为了叙述方便,这里设A>B>C>a>b>c
那么期望为:
(A-a)^2/3+(B-b)^2/3+(C-c)^2/3
再假设这里a>A,那么期望为:
-(A-a)^2/3+(B-b)^2/3+(C-c)^2/3
这里注意一点,为了保证精度,把分母放在最后除。
这样一个O(n^2)的算法就可以得到了:枚举每个A队员,再枚举每个B队员,可以得到期望。
优化?
//很多这样需要n^2优化至近似n的,大都有排序
我们注意到n^2的枚举有一个地方太累了:它每次都去比较A队员和B队员的大小,再加起来,如果我们对A,B队分别排序,就可以找到一个边界就结束,再者,这个边界还可以用二分加速。
举个例子。
Team A: A B C D E F
Team B:a  b  c d  e f
两个数列都是增序排序,现在枚举到队员A,找到B队中的c队员比他大,那么根据 (a-b)^2=a^2-2ab+b^2 容易知道前面肯定有2个a^2,2个b^2,后面有4个-a^2,4个-b^2.现在再讨论"ab",根据结合律,有sigma(ab)=a*sigma(b),这里对于b的处理就跟前面的b^2是一致的----记录前缀和。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iomanip>
using namespace std;
typedef long long ll;
typedef double D;
typedef long double LD;
ll a[100005]= {0},b[1000005]= {0};
ll n,sum1[100005]={0},sum2[1000005]={0};
int main() {
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
    sort(b+1,b+n+1);
    for(int i=1;i<=n;i++)
    {
        sum1[i]=sum1[i-1]+b[i];
        sum2[i]=sum2[i-1]+b[i]*b[i];
    }
    ll pointer=0;
    LD ans=0;
    for(int i=1;i<=n;i++)
    {
        while(a[i]>b[pointer+1]&&pointer<n)pointer++;
        ans+=a[i]*a[i]*(2*pointer-n); //前面pointer个,后面n-pointer个
        ans+=2*sum2[pointer]-sum2[n];
        ans-=2*a[i]*(2*sum1[pointer]-sum1[n]);
    }
    cout<<fixed<<setprecision(1)<<(ans/n);
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值