最优公式
题意
有一个长为 (n) 的数组 (A1,A2,…,An)。
你需要找到两个实数 (a), (b),使得 (sum_{i=1}^n sum_{j=1}^n max (|A_i - a|, |A_j - b|)) 尽可能小。
求出这个最小值。
容易发现答案乘上 2 一定是整数,求出答案乘上 2 模 (10^9+7) 的值。
分析
将一个点((x,y))的坐标变为((x+y,x-y))后,原坐标系中的曼哈顿距离 = 新坐标系中的切比雪夫距离
将一个点((x,y))的坐标变为((frac{x+y}{2},frac{x-y}{2}))后,原坐标系中的切比雪夫距离 = 新坐标系中的曼哈顿距离
将题意转化为(n^2)个点((A_i,A_j)),找到一个点((a,b)),使得这(n^2)个点和((a,b))的切比雪夫距离之和最小,将((A_i,A_j))转为((A_i+A_j,A_i-A_j)),因为答案要乘二,所以这样转化之后,求切比雪夫距离就变成了求曼哈顿距离。
因为所求的是曼哈顿距离,所以可以两个维度分别单独考虑,对于第一维(A_i+A_j),容易想到这(n^2)个点中从小到大第 (lfloor frac{n^2}{2} floor+1)个点到其他点的距离之和最小,可以二分这个点的大小(x),然后对每个(A_i)二分找到有多少个数(A_j)使得(A_i+A_j<x),找出第 (lfloor frac{n^2}{2} floor+1)个点后,同样可以这样对每个点二分计算贡献来计算答案,对第二维再做一遍类似的过程就可以了。
Code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<=n;++i)
#define per(i,n,a) for (int i=n;i>=a;--i)
#define sz(x) ((int)(x).size())
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
typedef pair<int,int> pii;
#define ll long long
const int inf=1e9;
const int mod=1e9+7;
const int N=1e5+10;
int n;
int a[N];
ll b[N];
bool ck(int x){
ll cnt=0;
rep(i,1,n) if(a[i]<=x){
int pos = lower_bound(a+1,a+n+1,x-a[i])-a-1;
cnt+=pos;
}
return cnt<=1ll*n*n/2;
}
bool ck1(int x){
ll cnt=0;
rep(i,1,n) {
int pos = upper_bound(a+1,a+n+1,a[i]-x)-a;
cnt+=n+1-pos;
}
return cnt<=1ll*n*n/2;
}
int main(){
ios::sync_with_stdio(false);
//freopen("in","r",stdin);
cin>>n;
rep(i,1,n) cin>>a[i];
sort(a+1,a+n+1);
rep(i,1,n) b[i]=(b[i-1]+a[i])%mod;
int l=1,r=1e9;
while(l<=r){
int mid=l+r>>1;
if(ck(mid)) l=mid+1;
else r=mid-1;
}
ll ans=0;
rep(i,1,n){
if(a[i]<=r){
int pos=upper_bound(a+1,a+n+1,r-a[i])-a-1;
ans=(ans-b[pos])%mod;
ans=(ans-1ll*pos*a[i]%mod)%mod;
ans=(ans+1ll*r*pos%mod)%mod;
int cpos=n-pos;
ans=(ans+1ll*a[i]*cpos%mod+b[n]-b[pos]-1ll*r*cpos%mod)%mod;
}else{
ans=(ans+b[n]+1ll*n*a[i]%mod-1ll*r*n%mod)%mod;
}
}
l=-1e9,r=1e9;
while(l<=r){
int mid=l+r>>1;
if(ck1(mid)) l=mid+1;
else r=mid-1;
}
rep(i,1,n){
int pos=lower_bound(a+1,a+n+1,a[i]-r)-a;
int cpos=n+1-pos;
ans=(ans+1ll*cpos*r%mod-1ll*a[i]*cpos%mod+b[n]-b[pos-1])%mod;
if(pos>0) ans=(ans-1ll*(pos-1)*r%mod+1ll*a[i]*(pos-1)%mod-b[pos-1])%mod;
}
ans=(ans%mod+mod)%mod;
cout<<ans<<endl;
return 0;
}