HDU 1394——Minimum Inversion Number(最小逆序数)

题意:

给定一个序列,里面的数是0到n-1,  每次要把第一个数放到最后一个数,重复n次,求n次操作中最小的逆序数是多少?


思路:

先求出初始的逆序数,然后每移动第一个数到最后面,那么逆序数要减去比它小的数的个数,加上比它大的数的个数。 如果我输入的数是a[i],那么比它小的数的个数就有a[i]个,比它大的数的个数就有n-1-a[i]个

方法:    归并排序树状数组线段树


归并排序代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define inf 0x3f3f3f3f
#define M 5001
using namespace std;
int ans,n;
int a[M],t[M],b[M];
void merge_sort(int *A,int x,int y,int *T)
{

    if(y-x>1){
        int m=(y+x)>>1;
        int p=x,q=m,i=x;
        merge_sort(A,x,m,T);
        merge_sort(A,m,y,T);
        while(p<m||q<y){
            if(q>=y||(p<m&&A[p]<=A[q])) T[i++]=A[p++];
            else {T[i++]=A[q++];ans+=m-p;}
        }
        for(i=x;i<y;++i){
            A[i]=T[i];
        }
    }
}
int main()
{
    //freopen("input.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        ans=0;
        for(int i=0;i<n;++i){
            scanf("%d",&a[i]);
            b[i]=a[i];     <span style="white-space:pre">		</span>
        }
        merge_sort(b,0,n,t); <span style="white-space:pre">		</span>//用临时数组排序求逆序数,因为我们还要引用原数组的数,
        int minn=ans;
        for(int i=0;i<n;++i){
            ans+=n-1-2*a[i];
            minn=min(minn,ans);
        }
        cout<<minn<<endl;
    }
    return 0;
}



树状数组 代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define inf 0x3f3f3f3f
#define M 5001
using namespace std;
int c[M],a[M],n;
int lowbit(int x)
{

    return x&-x;
}

void update(int x,int v)
{
    while(x<=n){
        c[x]+=v;
        x+=lowbit(x);
    }
}

int get_sum(int x)
{
    int ans=0;
    while(x>0){
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}
int main()
{
    //freopen("input.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        memset(c,0,sizeof c);
        int ans=0;
        for(int i=0;i<n;++i){
            scanf("%d",&a[i]);
            ans+=get_sum(n)-get_sum(a[i]+1);    <span style="white-space:pre">	</span>//求比a[i]大的个数
            update(a[i]+1,1);
        }

        //cout<<ans<<endl;
        int minn=inf;
        for(int i=0;i<n;++i){
            ans+=n-1-2*a[i];
            minn=min(minn,ans);
        }
        cout<<minn<<endl;
    }

    return 0;
}


线段树代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define M 5001
#define ls(x) x<<1
#define rs(x) x<<1|1
using namespace std;
int n;
int a[M];
struct node
{
    int l,r,num;
}tre[4*M];
void push_up(int rt)
{
    tre[rt].num=tre[ls(rt)].num+tre[rs(rt)].num;
}
void build(int rt,int l,int r)
{
    tre[rt].l=l;
    tre[rt].r=r;
    tre[rt].num=0;
    if(l==r) return;
    int m=(l+r)>>1;
    build(ls(rt),l,m);
    build(rs(rt),m+1,r);
    push_up(rt);

}
void update(int rt,int p,int v)
{
    if(tre[rt].l==tre[rt].r){
        tre[rt].num=v;
        return;
    }
    int m=(tre[rt].l+tre[rt].r)>>1;
    if(p<=m) update(ls(rt),p,v);
    else update(rs(rt),p,v);
    push_up(rt);

}
int get_sum(int rt,int l,int r)
{
    if(l<=tre[rt].l&&tre[rt].r<=r){
        return tre[rt].num;
    }
    int sum=0;
    int m=(tre[rt].l+tre[rt].r)>>1;
    if(l<=m) sum+=get_sum(ls(rt),l,r);
    if(m<r) sum+=get_sum(rs(rt),l,r);
    return sum;
}
int main()
{
    //freopen("input.txt","r",stdin);
    while(scanf("%d",&n)!=EOF){
        build(1,0,n-1);
        int ans=0;
        for(int i=0;i<n;++i){
            scanf("%d",&a[i]);
            ans+=get_sum(1,a[i]+1,n-1);   //求比a[i]大的数的个数
            update(1,a[i],1);
        }
        int minn=ans;
        for(int i=0;i<n;++i){
            ans+=n-1-2*a[i];
            minn=min(minn,ans);
        }
        cout<<minn<<endl;

    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值