涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2
其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。
考虑交换对距离的影响
交换前(a1-b1)^2+(a2-b2)^2
交换后(a2-b1)^2+(a1-b2)^2
发现两火柴距离中Σai²是交换不掉的,会交换改变的是-2aibi。
题目变成了使得Σaibi尽量大。贪心发现,排序后对应位置时aibi最大。
把两个排序记录对应关系建立映射,按照原来的某一数组顺序,给另外数组的目标状态映射出来。将目标状态求逆序对。
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
const int MOD=99999997;
int n;
int a[MAXN];
struct data{
int val,pos;
}b[MAXN],c[MAXN];
int num=0;
bool cmp(data a,data b){
return a.val<b.val;
}
bool cmp2(data a,data b){
return a.val>b.val;
}
int sumv[MAXN<<2];
struct xds{
#define lson (o<<1)
#define rson (o<<1|1)
inline void pushup(int o){sumv[o]=((sumv[lson]%MOD)+(sumv[rson])%MOD);sumv[o]%=MOD;}
inline void change(int o,int l,int r,int pos){
if(l==r){sumv[o]++;sumv[o]%=MOD;return;}
int mid=l+r>>1;
if(pos<=mid)change(lson,l,mid,pos);
else change(rson,mid+1,r,pos);
pushup(o);
}
inline int query(int o,int l,int r,int ql,int qr){
if(ql<=l&&qr>=r){return sumv[o];}
int mid=l+r>>1,ans=0;
if(ql<=mid)(ans+=query(lson,l,mid,ql,qr))%=MOD;
if(qr>mid)(ans+=query(rson,mid+1,r,ql,qr))%=MOD;
return ans%MOD;
}
}T;
map<int,int>ma;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),c[i].val=a[i];
for(int i=1;i<=n;i++)
scanf("%d",&b[i].val),b[i].pos=i;
sort(a+1,a+1+n);
sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++){
ma[a[i]]=b[i].pos;
}
for(int i=1;i<=n;i++){
c[i].val=ma[c[i].val];
c[i].pos=i;
}
sort(c+1,c+1+n,cmp2);
int ans=0;
for(int i=1;i<=n;i++){
if(c[i].pos!=1)(ans+=T.query(1,1,n,1,c[i].pos-1))%=MOD;
T.change(1,1,n,c[i].pos);
}
printf("%d\n",ans%=MOD);
return 0;
}