题面:已知有1到n的排列,每个数可以加1或是加0,求逆序数最小是多少。
解析:一个排序的逆序数已经是固定的,逆序数减少就说明一个数字x的后面出现了x-1,x不变,x-1再加1。记录逆序数减少的个数,可以从后往前推,用h[]存数字是否出现,加以判断即可。
求逆序数用树状数组。
代码:
#include<stdio.h>
#include<algorithm>
#define MAXN 5000001
using namespace std;
typedef long long ll;
ll bt[MAXN]={0},n,h[MAXN],ans;
ll a[MAXN];
void add(ll x,ll k){
while(x<=n){
bt[x]+=k;
x+=x&(-x);
}
}
ll sum(ll x){
ll ans=0;
while(x){
ans+=bt[x];
x-=x&(-x);
}
return ans;
}
int ha[MAXN]={0};
int t;
ll cn=0;
int main(){
// scanf("%d",&t);
// while(t--){
scanf("%lld",&n);
for(ll i=1;i<=n;i++){
scanf("%lld",&a[i] );
}
for(ll i=1;i<=n;i++){
add(a[i],1);
ans+=i-sum(a[i]);
}//求逆序数
ha[n+1]=1;//使n不能加1
for(int i=n;i>0;i--)
if(ha[a[i]]==0&&ha[a[i]+1]==0)//如果a[i]和a[i+1]都没出现过
{cn++;ha[a[i]]=1;ha[a[i]+1]=1;}
else if(ha[a[i]]==0&&ha[a[i]+1]==1) ha[a[i]]=1;//标记a[i]
printf("%lld\n",ans-cn);
//}
}


京公网安备 11010502036488号