牛客挑战赛43 C-最优公式 二分,切比雪夫距离转曼哈顿距离

最优公式

题意

有一个长为 \(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} \rfloor+1\)个点到其他点的距离之和最小,可以二分这个点的大小\(x\),然后对每个\(A_i\)二分找到有多少个数\(A_j\)使得\(A_i+A_j<x\),找出第 \(\lfloor \frac{n^2}{2} \rfloor+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;
}
posted @ 2020-09-22 17:48  xyq0220  阅读(158)  评论(0编辑  收藏  举报