b_lq_小朋友排队(归并排求逆序对+前n项和)

某个小朋友第 k 次交换时,他的不高兴程度增加 k。
请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。

输入:
3
3 2 1
输出:9
解释:<3,2>交换(2,3,1),<3,1>交换(2,1,3),<1,2>交换(1,2,3)
1、2、3都被交换了两次,所以不开心值都为1+2=3,总为9

思路
这其实就是在求每个数字在逆序对中出现的次数

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
struct node {
    ll h,c;
} a[N], b[N];
void merge_sort(int l, int r) {
    if (l==r) return;
    int m=l+r>>1;
    merge_sort(l,m), merge_sort(m+1, r);
    int i=l, j=m+1, k=l;
    while (i<=m && j<=r) {
        //a[i].h<=a[j].h,则证明[m,j]的身高都不比a[i]高。为什么?因为只有a[i]>a[j]时,指针j才会移动
        if (a[i].h<=a[j].h) b[k]=a[i++], b[k++].c+=j-m-1;
        else                b[k]=a[j++], b[k++].c+=m-i+1;
    }
    while (i<=m) b[k]=a[i++], b[k++].c+=j-m-1; //i没有走完,表示[m,j]这些人的身高都小于a[i].h,也就是和a[i].h组成了j-m-1个逆序对
    while (j<=r) b[k]=a[j++], b[k++].c+=m-i+1; //j没有走完,表示[
    for (int p=l; p<=r; p++) a[p]=b[p];
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int n; cin>>n;
    for (int i=0; i<n; i++) cin>>a[i].h, a[i].c=0;
    merge_sort(0,n-1);
    ll ans=0;
    for (int i=0; i<n; i++) {
        ll x=a[i].c;
        ans+=(x+1)*x/2ll;
    }
    cout<<ans;
    return 0;
}
posted @ 2020-10-03 17:40  童年の波鞋  阅读(105)  评论(0编辑  收藏  举报