「NOIP 2013」火柴排队 题解

题目描述

涵涵有两盒火柴,每盒装有 nn 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: ( a i b i ) 2 \sum (a_i-b_i)^2

其中 a i a_i 表示第一列火柴中第 i i 个火柴的高度, b i b_i 表示第二列火柴中第 i i 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 1 0 8 3 10^8-3 取模的结果。

输入格式

共三行,第一行包含一个整数 n n ,表示每盒中火柴的数目。
第二行有 n n 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有 n n 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式

一个整数,表示最少交换次数对 1 0 8 3 10^8-3 取模的结果。

输入输出样例

输入

4
1 3 4 2
1 7 2 4

输出

2

数据范围

1 n 1 0 5 1 \leq n \leq 10^5 0 0 \leq 火柴高度 2 31 \leq 2^{31}。

分析

好,一开始我们数学推一波。
欲求 m i n ( ( a i b i ) 2 ) ( 1 i n ) min(\sum (a_i - b_i)^2)(1 \leq i \leq n)
即求 m i n ( a i 2 + b i 2 2 a i b i ) min(\sum a_i^2 + \sum b_i^2 - \sum 2a_ib_i)
因为 a i 2 \sum a_i^2 b i 2 \sum b_i^2 为定值。
即求 m a x ( 2 a i b i ) max(\sum 2a_ib_i)
即求 m a x ( a i b i ) max(\sum a_ib_i)
A 1 > A 2 A_1 > A_2 B 1 > B 2 B_1 > B_2
按照生活常识易知
A 1 B 2 + A 2 B 1 A 1 B 1 + A 2 B 2 A_1B_2 + A_2B_1 \leq A_1B_1 + A_2B_2
好吧如果你问为什么,
我也不知道 A 2 B 1 A_2B_1 移到不等式右边, A 1 B 1 A_1B_1 移到不等式左边,提个 A 1 A_1 A 2 A_2 出来你总知道了吧。
说得通俗一点,就是要让最大乘最大,最小乘最小,才能得到整体最大。
做法就很明显了,将两数组排序,让相同下标的两数一一对应。输入时令 a [ i ] . n u m = i a[i].num=i b [ i ] . n u m = i b[i].num=i 。(离散化)我们需要在两数组从小到大排序后仍使 a [ i ] . n u m = = b [ i ] . n u m a[i].num==b[i].num 。定义 m p mp 数组 m p [ a [ i ] . n u m ] = b [ i ] . n u m mp[a[i].num] = b[i].num 。则需使 m p [ i ] = i mp[i]=i 。即求从小到大排序 m p mp 数组的最小步数。即求此数组中逆序对的个数。(板子)
好的,分析完毕。

代码

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <climits>
#include <cstring>
#include <map>
using namespace std;
const int MAXN = 1e5 + 5, Mod = 99999997;
struct Node {
	int X, num;
};
Node a[MAXN], b[MAXN];
int mp[MAXN], c[MAXN];
int n, ans;
bool cmp(Node x, Node y) {
	return x.X < y.X;
}
void Sort(int l, int r) {//归并 
    if(l == r) return;
    int mid = (l + r) >> 1;
    Sort(l, mid);
    Sort(mid + 1, r);
    int flag = l, i = l, j = mid + 1;
    while(i <= mid && j <= r) {
        if(mp[i] <= mp[j]) {
            c[flag] = mp[i];
            flag ++; i ++;
        }
		else {
            c[flag] = mp[j];
            flag ++; j ++;
			ans = (ans + (mid - i + 1)) % Mod;
        }
    }
    while(i <= mid) {
        c[flag] = mp[i];
        i ++; flag ++;
    }
    while(j <= r) {
        c[flag] = mp[j];
        j ++; flag ++;
    }
    for(int i = l; i <= r; i ++) mp[i] = c[i];
}
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i ++) {
		scanf("%d", &a[i].X);
		a[i].num = i;//有离散化的思想 
	}
	for(int i = 1; i <= n; i ++) {
		scanf("%d", &b[i].X);
		b[i].num = i;
	}
	sort(a + 1, a + 1 + n, cmp);
	sort(b + 1, b + 1 + n, cmp);
	for(int i = 1; i <= n; i ++) {
		mp[a[i].num] = b[i].num;
	}
	Sort(1, n);
	printf("%d", ans);
	return 0;
}

谢谢观看,欢迎指出错误&问问题。

猜你喜欢

转载自blog.csdn.net/Clever_Hard/article/details/107253759