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