解题思路
考试的时候已经推出来了,结果没想着化简TOT, n 2 n^2 n2拿30分…
我们考虑选中 A 1 A_1 A1和 B 1 B_1 B1了,则剩下的A和B共有 ! ( n − 1 ) !(n-1) !(n−1)种组合方案,而总共有!n种组合方案,则 A 1 A_1 A1和 B 1 B_1 B1的组合下可以贡献的期望为 ( A 1 − B 1 ) 2 ∗ ! ( n − 1 ) ! n \frac{(A_1-B_1)^2*!(n-1)}{!n} !n(A1−B1)2∗!(n−1)
简化得 ( A 1 − B 1 ) 2 n \frac{(A_1-B_1)^2}{n} n(A1−B1)2
所以题目要求的是:
其中正负由
a
[
i
]
a[i]
a[i]和
b
[
i
]
b[i]
b[i]的大小关系决定分值的正负,正负的处理可以对b排序,比a[i]大的取负,比a[i]小的取正,上面的式子展开之后可以得到:
我们把A和排序,预处理b的前缀和
b
2
b^2
b2的前缀和,每次只用枚举
A
i
A_i
Ai,统计
a
n
s
ans
ans加上
A
i
A_i
Ai与比它小的
B
i
B_i
Bi的正贡献,减去
A
i
A_i
Ai与比它小的
B
i
B_i
Bi的负贡献,就好了。(这里在找比
A
i
A_i
Ai小的
B
i
B_i
Bi时可以用一个指针不断右移得到)
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#define ll long long
#define ldb long double
using namespace std;
ldb ans;
ll a[50010],b[50010],sum[50010],q[50010];
ll w,n;
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
scanf("%lld",&b[i]);
sort(a+1,a+n+1);
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+b[i];
q[i]=q[i-1]+pow(b[i],2);
}
int x=0;
for(int i=1;i<=n;i++)
{
while(a[i]>b[x+1]&&x<n)x++;
ans+=(x*pow(a[i],2)+q[x]-2*a[i]*sum[x])*1.0/n*1.0;
ans-=((n-x)*pow(a[i],2)+q[n]-q[x]-2*a[i]*(sum[n]-sum[x]))*1.0/n*1.0;
}
printf("%.1Lf",ans);
}