【NOIP2013提高组】火柴排队
https://www.luogu.org/problem/show?pid=1966
Σ(ai-bi)2=Σai2+Σbi2-2Σai*bi,要使Σ(ai-bi)2最小,则需2Σai*bi最大。
由排序不等式可知两列数字里第一大与第一大对应,第二大与第二大对应,……,第k大与第k大对应,……,第n大与第n大对应时,Σai*bi最大。
故先将第一列每个数字映射到第二列排名相同的数字,再求需要交换的次数,也就是逆序对的个数。
#include <algorithm> #include <iostream> #include <vector> #define maxn 100005 typedef long long llint; using namespace std; int n; llint tmp[maxn], sorted[maxn], cnt = 0; void merge_sort(int l, int r) { if (l == r) return; int mid = (l + r) / 2; merge_sort(l, mid); merge_sort(mid + 1, r); int p1 = l, p2 = mid + 1, p = l; while (p1 <= mid && p2 <= r) { if (sorted[p1] <= sorted[p2]) tmp[p++] = sorted[p1++]; else { cnt = (cnt + (mid - p1 + 1)) % 99999997; tmp[p++] = sorted[p2++]; } } while (p1 <= mid) tmp[p++] = sorted[p1++]; while (p2 <= r) tmp[p++] = sorted[p2++]; for (int i = l; i <= r; i++) sorted[i] = tmp[i]; } template <class T> void print(T *p) { for (int i = 1; i <= n; i++) cout << p[i] << ' '; cout << endl; } pair<llint, llint> a[maxn], b[maxn]; int rnk[maxn]; int main() { ios::sync_with_stdio(false); cin >> n; for (int i = 1; i <= n; i++) { cin >> a[i].first; a[i].second = i; } for (int i = 1; i <= n; i++) { cin >> b[i].first; b[i].second = i; } sort(a + 1, a + n + 1); sort(b + 1, b + n + 1); for (int i = 1; i <= n; i++) sorted[a[i].second] = b[i].second; // 将第一列排第i名的项与第二列排第i名的项对应 merge_sort(1, n); cout << cnt << endl; return 0; }