たのしい家庭菜園
前置知识:对于一个序列,只能相邻两两交换时,排成有序序列的最小次数为逆序对的个数。
而交换较小的两个数时,对较大的数没有影响,就是满足条件的还是满足条件,不满足的还是不满足
先从大到小排序,得到序列的相对位置(原下标),然后依次插入i
题目要求最后的序列先不递减再不递增,所以中间那个一定放最高的,然后往两边依次放。
那么现在只需要思考怎么让新序列的逆序对数最少
当放入一个数的时候,判断放左边和右边哪个产生的逆序对数少,贪心的选即可。在原序列中,将左侧大于i的数的数
目记为Li,右侧大于i的数的数目记为Ri,
那么如果将一个点放在新序列的左侧,贡献的逆序对就是Li,反之为Ri。
根据性质:相邻交换次数等于逆序对数,我们对于每个数选取min{Li,Ri}加上去就可以了
#include <bits/stdc++.h>
using namespace std;
const int N=300005;
struct qq{
int x,id;
}a[N];
long long s[N];
long long ans=0;
int n;
int cmp(qq x,qq y) {
return x.x>y.x;
}
long long lowbit(long long x) {
return x&(-x);
}
void add(long long x)
{
while(x<=n)
{
s[x]++;
x+=lowbit(x);
}
}
long long getsum(long long x)
{
long long sum=0;
while(x>0)
{
sum+=s[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i].x);
a[i].id=i;
}
memset(s,0,sizeof(s));
sort(a+1,a+n+1,cmp);
int st=1;
for(int i=1;i<=n;i++) {
if(a[i].x!=a[i-1].x) {
while(st<i)
add(a[st++].id);
}
int soy=getsum(a[i].id);
ans+=min(soy,st-1-soy);
}
printf("%lld",ans);
return 0;
}
本文来自博客园,作者:Doria_tt,转载请注明原文链接:https://www.cnblogs.com/pangtuan666/p/16558681.html

浙公网安备 33010602011771号