题目:
涵涵有两盒火柴,每盒装有n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ∑(ai-bi)^2其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。
请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 99,999,997 取模的结果。
输入:
4
2 3 1 4
3 2 1 4
输出:
1
题解:
我们不难发现其实若要最后距离最短其实就是|ai-bi|最小,所以为了达到这种效果只需让最大和最大作差,次大和次大依次作差,所以首先排序(要保存原位置下标),然后再将a数组的所有火柴在b数组中找到对应,最后最在数组里,求数组的逆序对即可(因为此事数组最大和最大,次大和次大应该一一对应,若出现有a[i] > a[j] && i < j的情况就需要转换,即使操作++)
最后求逆序对可以用二路归并排序,记录操作次数
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
long long n, sum[1000005], c[1000005], ans;
void er_Sort(long long qi, long long len) {
if(qi == len){
return ;
}
int mid = (qi + len) / 2;
er_Sort(qi, mid);
er_Sort(mid + 1, len);
long long i = qi;
long long j = mid + 1;
long long k = qi;
while(i <= mid && j <= len) {
if(sum[i] <= sum[j]){
c[k] = sum[i];
i ++;
k ++;
}
else {
c[k] = sum[j];
ans = ans + mid - i + 1;//出现逆序对
j ++;
k ++;
}
}
while(i <= mid) {
c[k] = sum[i];
i ++;
k ++;
}
while(j <= len) {
c[k] = sum[j];
j ++;
k ++;
}
for(int i = qi; i <= len;i ++) {
sum[i] = c[i];
}
}
struct jj{
long long s, xiabiao;
}a[100005], b[100005];
int cmp(jj x, jj y) {
return x.s < y.s;
}
int main() {
scanf("%lld", &n);
for(int i = 1;i <= n; i++) {
scanf("%lld", &a[i].s);
a[i].xiabiao = i;
}
for(int i = 1;i <= n; i++) {
scanf("%lld", &b[i].s);
b[i].xiabiao = i;
}
sort(a + 1, a + 1 + n, cmp);
sort(b + 1, b + 1 + n, cmp);
for(int i = 1;i <= n; i++) {
sum[b[i].xiabiao] = a[i].xiabiao;
}
er_Sort(1, n);
printf("%lld", ans % 99999997);
return 0;
}