[NOIP2013 提高组] 火柴排队

题目【逆序对应用】

思路

  • 首先,什么状态是目标状态
  • 即(ai-bi)^2 最小的状态=ai^2+bi^2-2aibi
  • ai^2与bi^2不变, 主要要求sum(aibi)最大
  • 可以证明,第二列的大小顺序与第一列保持一致最大 即aibi差距最小最大
  • 令x[sx[i]] = sx[i]
  • x的逆序对即为需要交换的次数

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;
const int mod = 1e8-3;
int res=0;

struct Node {
    int v,id;
    bool operator<(const Node& t) const {
        return v<t.v;
    }
}a[N], b[N];
int x[N];
int tmp[N];

void msort(int l, int r)  // 归并排序
{
    if(l >= r) return;
    int mid = l+r>>1;
    msort(l,mid), msort(mid+1, r);
    //合并两个有序数组
    int i=l, j=mid+1, k=0;
    while(i<=mid && j<=r) {
        if(x[i]<=x[j]) {
            tmp[k++] = x[i++];
        }else {
            res = (res + mid-i+1)%mod;
            tmp[k++] = x[j++];
        }
    }
    while(i<=mid) tmp[k++] = x[i++];
    while(j<=r) tmp[k++] = x[j++];
    for(int i=l; i<=r; ++i) x[i] = tmp[i-l];//还是[l,r]好
}


int n;
int main()
{
    cin>>n;
    for(int i=1; i<=n; ++i) {
        scanf("%d", &a[i].v);
        a[i].id = i;
    }
    for(int i=1; i<=n; ++i) {
        scanf("%d", &b[i].v);
        b[i].id = i;
    }
    sort(a+1,a+n+1);
    sort(b+1,b+n+1);
    
    for(int i=1; i<=n; ++i) {
        x[a[i].id] = b[i].id;
    }
    
    msort(1,n);
    cout<<res;
    return 0;
}
posted @ 2021-08-23 12:50  misaka-mikoto  阅读(40)  评论(0编辑  收藏  举报