求循环变换序列中逆序对的个数

来源:互联网 发布:西门子工业软件报价 编辑:程序博客网 时间:2024/06/01 14:44

求序列中逆序对的个数


方法一:暴力O(N^2)

int cnt = 0;for(int i=0;i<n;i++){    for(int j=0;j<i;j++)    {        if(a[j]>a[i])            cnt++;    }}


方法二:线段树

先建一棵空树,每个叶子节点代表序列中数的对应位置。

每次插入一个数x[i]之前,询问在x[i]之前插入的比它大的数的个数,

即x[i]到n-1段的数的个数。

然后插入x[i],更新相应段的数的个数。


(感觉就是 用线段树储存然后模拟插入排序  找逆序对的个数,利用了插入时间的先后)


hdu 1394

#include<cstdio>#include<iostream>#include<cstring>#define maxn 5010using namespace std;int sum[maxn<<2],x[maxn];void PushUP(int rt){    sum[rt] = sum[rt<<1]+sum[rt<<1|1];}void build(int l,int r,int rt){    sum[rt] = 0;    if(l==r) return ;    int mid = (l+r)>>1;    build(l,mid,rt<<1);    build(mid+1,r,rt<<1|1);    PushUP(rt);}void update(int l,int r,int rt,int pos){    if(l==r)    {        sum[rt]++;        return ;    }    int mid = (l+r)>>1;    if(pos<=mid) update(l,mid,rt<<1,pos);    else update(mid+1,r,rt<<1|1,pos);    PushUP(rt);}int que(int l,int r,int rt,int le,int ri){    if(le<=l && r<=ri)        return sum[rt];    int mid = (l+r)>>1;    int res = 0;    if(le<=mid) res+=que(l,mid,rt<<1,le,ri);    if(ri>mid) res+=que(mid+1,r,rt<<1|1,le,ri);    return res;}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        build(0,n-1,1);        int cnt = 0;        for(int i=1;i<=n;i++)        {            scanf("%d",&x[i]);            cnt += que(0,n-1,1,x[i],n-1);            update(0,n-1,1,x[i]);        }        int ans = cnt;        for(int i=1;i<=n;i++)        {            cnt = cnt+(n-1-x[i])-x[i];            if(cnt<ans) ans = cnt;        }        printf("%d\n",ans);    }    return 0;}


方法三:归并排序


关于循环变换后逆序对的个数可以由当前的逆序对个数递推得到。

x[i]是0~n-1连续的数列,有x[i]个数比x[i]小。

把x[i]放到最后,则逆序对个数   减少了x[i],增加了n-1-x[i]。



0 0
原创粉丝点击