复习题解集——火柴排队

题目:

涵涵有两盒火柴,每盒装有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;
}

猜你喜欢

转载自blog.csdn.net/cqbz_lipengcheng/article/details/107282011