【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;
}

 

posted @ 2017-09-16 16:59  ssttkkl  阅读(262)  评论(0编辑  收藏  举报