September 3rd 模拟赛C T2 比赛 Solution

空降题目处(外网)
点我点我点我

空降题目处(内网)
点我点我点我

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多少分。答案保留到小数点后一位(注意精度)。

Solution

可理解为 A 不变,B做全排列来匹配.
但是这样是 O(N!) 的.与题意不符.
所以,我们可以将 B 排序,做它的前缀和X与前缀平方和 Y .
B中二分 k ,即Bk Ai 小时, k 取最大.
然后就是推公式.
i=1n
A 队正分:
((AiB1)2+(AiB2)2++(AiBk1)2+(AiBk)2)(N1)!N
=(Ai2AiB1+B1)+(Ai2AiB2+B2)++(Ai2AiBk1+Bk1)+(Ai2AiBk+Bk)N
=(Aik2AiXj+Yj)N
A 队负分:
((AiBk+1)2+(AiBk+2)2++(AiBN1)2+(AiBN)2)(N1)!N
=(Ai2AiBk+1+Bk+1)+(Ai2AiBk+2+Bk+2)++(Ai2AiBN1+BN1)+(Ai2AiBN+BN)N
=(Ai(Nk)2Ai(XNXj)+(YNYj))N
即:
Ans=Ni=1(Aik2AiXj+Yj)(Ai(Nk)2Ai(XNXj)+(YNYj))N
还有神奇的精度问题…
这里写图片描述
这里写图片描述
我都不想说话了…
自己调吧,我帮不了你…
头晕?歇菜了?见Code 滑稽

Code

C++

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;

double ans,x[50001],y[50001],a[50001],b[50001];
int n,t,j=1;

int bs(int l,int r,double d);
int get(int x);

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%lf",&a[i]);
    for (int i=1;i<=n;i++)
        scanf("%lf",&b[i]);
    sort(b+1,b+n+1);
    for (int i=1;i<=n;i++)
    {
        x[i]=x[i-1]+b[i];
        y[i]=y[i-1]+b[i]*b[i];
    }
    for (int i=1;i<=n;i++)
    {
        t=get(i);
        j=t;
        ans+=(a[i]*a[i]*(double)(t)-2*a[i]*x[t]+y[t])*1000/n;
        ans-=(a[i]*a[i]*(double)(n-t)-2*a[i]*(x[n]-x[t])+(y[n]-y[t]))*1000/n;
    }
    printf("%.1lf",ans/1000);
}

int bs(int l,int r,double d)
{
    if (l>=r)
        return l;
    int m=(l+r)/2;
    if (d<b[m+1])
        return bs(l,m,d);
    else
        return bs(m+1,r,d);
}

int get(int x)
{
    int value=0;
    int l=1,r=n,mid;
    while (l<=r)
    {
        mid=(l+r)/2;
        if (b[mid]>a[x]) r=mid-1;
        else {l=mid+1;value=mid;}
    }
    return(value);
}

Pascal

var
        a,b,sq,pre:array[0..50000] of int64;
        i,j,n:longint;
        score_a,score_b:int64;
procedure qsort_a(l,r:longint);
var
        i,j,mid:longint;
begin
        i:=l;
        j:=r;
        mid:=a[(i+j) div 2];
        repeat
                while a[i]<mid do inc(i);
                while a[j]>mid do dec(j);
                if i<=j then
                begin
                        a[0]:=a[i];
                        a[i]:=a[j];
                        a[j]:=a[0];
                        inc(i);
                        dec(j);
                end;
        until i>j;
        if l<j then qsort_a(l,j);
        if i<r then qsort_a(i,r);
end;
procedure qsort_b(l,r:longint);
var
        i,j,mid:longint;
begin
        i:=l;
        j:=r;
        mid:=b[(i+j) div 2];
        repeat
                while b[i]<mid do inc(i);
                while b[j]>mid do dec(j);
                if i<=j then
                begin
                        b[0]:=b[i];
                        b[i]:=b[j];
                        b[j]:=b[0];
                        inc(i);
                        dec(j);
                end;
        until i>j;
        if l<j then qsort_b(l,j);
        if i<r then qsort_b(i,r);
end;
begin
        readln(n);
        for i:=1 to n do read(a[i]);
        for i:=1 to n do read(b[i]);
        qsort_a(1,n);
        qsort_b(1,n);
        sq[0]:=0;
        for i:=1 to n do
                sq[i]:=sq[i-1]+sqr(b[i]);
        pre[0]:=0;
        for i:=1 to n do
                pre[i]:=pre[i-1]+b[i];
        i:=1;
        j:=0;
        score_a:=0;
        repeat
                while (b[j+1]<a[i])and(j+1<=n) do inc(j);
                score_a:=score_a+j*sqr(a[i])+sq[j]-2*a[i]*pre[j];
                inc(i);
        until i>n;
        sq[0]:=0;
        for i:=1 to n do
                sq[i]:=sq[i-1]+sqr(a[i]);
        pre[0]:=0;
        for i:=1 to n do
                pre[i]:=pre[i-1]+a[i];
        i:=1;
        j:=0;
        score_b:=0;
        repeat
                while (a[j+1]<b[i])and(j+1<=n) do inc(j);
                score_b:=score_b+j*sqr(b[i])+sq[j]-2*b[i]*pre[j];
                inc(i);
        until i>n;
        writeln((score_a-score_b)/n:0:1);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值