题目链接:
思路:
题目要求的是(ai - bi)^2的最小值,由于ai^2 + bi^2是不变的,不同组合只会带来(-2ai*bi)的不同,也就是说我们要找出让(ai*bi)最大的方案,容易知道,小的数字和小的数字组合起来会让乘积加起来最大化(证明略)
所以,考虑将两个数组的数字离散化,然后做数组映射。再求第二个数组的逆序对数的和,就是答案。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
const int mod = 1e8-3;
int n;
struct node{int x,id;} a1[maxn], b1[maxn]; //node{离散前数值,下标}
int a2[maxn], b2[maxn]; //离散后的数组
bool cmp(const node&a, const node&b){return a.x<b.x;}
int mp[maxn]; //从a2到b2进行映射的数组
long long sum = 0; //逆序数
int tmp[maxn]; //临时数组
void merge(int left, int right){ //归并排序,顺便求逆序数
if(left >= right) return;
int mid = left + (right-left)/2;
merge(left,mid); merge(mid+1, right);
int i = left, j = mid+1, t = left;
while(i<=mid && j<=right){
if(b2[i] <= b2[j]) tmp[t++] = b2[i++];
else {sum += mid-i+1; sum%=mod; tmp[t++] = b2[j++];}
}
while(i<=mid) tmp[t++] = b2[i++];
while(j<=right) tmp[t++] = b2[j++];
for(int k=left; k<=right; k++) b2[k] = tmp[k];
}
void read(){ //读入数据,并且进行离散化
cin>>n;
for(int i=1; i<=n; i++){cin>>a1[i].x; a1[i].id=i;}
for(int i=1; i<=n; i++){cin>>b1[i].x; b1[i].id=i;}
sort(a1+1,a1+n+1,cmp);
sort(b1+1,b1+n+1,cmp);
for(int i=1; i<=n; i++){a2[a1[i].id]=i;}
for(int i=1; i<=n; i++){b2[b1[i].id]=i;}
}
int main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
read();
for(int i=1; i<=n; i++)
mp[a2[i]] = i; //反向记录映射
for(int i=1; i<=n; i++)
b2[i] = mp[b2[i]]; //把b2中数字进行映射
merge(1,n); //1~n范围内进行归并排序求逆序对
cout << sum;
}