题目描述
涵涵有两盒火柴,每盒装有 nn 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: \sum (a_i-b_i)^2∑(a
i
−b
i
)
2
其中 a_ia
i
表示第一列火柴中第 i i个火柴的高度,b_ib
i
表示第二列火柴中第 ii 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 99,999,997取模的结果。
输入输出格式
输入格式:
共三行,第一行包含一个整数 nn,表示每盒中火柴的数目。
第二行有 n n个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有 nn 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
输出格式:
一个整数,表示最少交换次数对 99,999,99799,999,997 取模的结果。
输入输出样例
输入样例#1:
4
2 3 1 4
3 2 1 4
输出样例#1:
1
输入样例#2:
4
1 3 4 2
1 7 2 4
输出样例#2:
2
思路
- 可以发现,要满足条件,即要使两列火柴小对小,大对大
- 让ab数组由小到大排列,同时保存id
- 我们令 q[a[i]] = b[i],相当于以 a[i] 为关键字对序列b[i] 排序。
- 若序列a 与序列 b 相等,那么此时 q[a[i]] 应该等于 a[i]的,也就是 q[i] = i
- 那么也就是说如果我们想让序列 a 与序列 b 相等,那么我们需要让 q 升序排列
- 问题就变为,将原本乱的 q 序列升序排列的最少交换次数
- (代码中q数组为a1)
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define mod 99999997
#define N 100005
struct matches{
int v,id;
}a[N],b[N];
int n,id;
int a1[N],b1[N];
long long ans;
bool Cmp(const matches a,const matches b){
if(a.v==b.v) return a.id<b.id;
return a.v<b.v;
}
void merge(int l,int m,int r){
int i=l,k=l,j=m+1;
while(i<=m && j<=r)
if(a1[i]<=a1[j]) b1[k++] = a1[i++];
else ans += m-i+1,ans%=mod,b1[k++] = a1[j++];
while(i <= m) b1[k++] = a1[i++];
while(j <= r) b1[k++] = a1[j++];
for(int i=l; i<=r; i++) a1[i] = b1[i];
}
void merge_sort(int l,int r){
if(l == r) return;
int m = (l+r)>>1;
merge_sort(l,m);
merge_sort(m+1,r);
merge(l,m,r);
}
int main()
{
// freopen("match.in","r",stdin);
// freopen("match.out","w",stdout);
scanf("%d",&n);
for(int i=1; i<=n; i++){
scanf("%d",&a[i].v);
a[i].id = i;
}
for(int i=1; i<=n; i++){
scanf("%d",&b[i].v);
b[i].id = i;
}
sort(a+1,a+1+n,Cmp);
sort(b+1,b+1+n,Cmp);
for(int i=1; i<=n; i++)
a1[b[i].id] = a[i].id;
//求逆序
merge_sort(1,n);
printf("%lld",ans);
return 0;
}