zoukankan      html  css  js  c++  java
  • 逆序对

    逆序对目前我所知的有三种解法

    首先是最简单的冒泡排序,当每次前面一个数比后面一个数大时就会交换,因此可以用冒泡排序来求逆序对

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
    	int n,sum=0;
    	cin>>n;
    	int a[10001];
    	for(int i=1;i<=n;i++) scanf("%d
    ",&a[i]);
    	for(int i=1;i<=n;i++)
    	    for(int j=i+1;j<=n;j++)
    	        if(a[i]>a[j]) sum++;
    	printf("%d",sum);
    	return 0;
    }
    

    两个(for)循环,复杂度为(O(n^2))


    接下来是归并排序,由于每次(merge)的时候会判断数的大小,所以归并排序可以用来求逆序对

    代码:

    #include<cstdio>
    #define ll long long 
    using namespace std;
    const int maxn=5e5+5;
    
    int a[maxn],r[maxn],n;
    ll ans=0;
    void msort(int s,int t){
    	if(s==t) return ;
    	int mid=s+t>>1;
    	msort(s,mid),msort(mid+1,t);
    	int i=s,j=mid+1,k=s;
    	while(i<=mid&&j<=t)
    		if(a[i]<=a[j]) r[k++]=a[i++];
    		else r[k++]=a[j++],ans+=(ll)mid-i+1;
    	while(i<=mid) r[k]=a[i],k++,i++;
    	while(j<=t) r[k]=a[j],k++,j++;
    	for(int i=s;i<=t;i++) a[i]=r[i]; 
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	msort(1,n);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    复杂度为(O(nlogn))


    最后是树状数组的解法

    首先需要把数组离散化,然后从小到大排序,加入树状数组里维护

    由于排完序是从小到大丢到树状数组里面的

    所以现在加入的数字一定比之后加入的数字大

    查询这个数前面的数就可以求得逆序对的个数了

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll N=500005;
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*f;
    }
    ll n,a[N],b[N],f[N],ans;
    inline bool cmp(const ll &i,const ll &j){return b[i]>=b[j];}
    inline ll lowbit(ll x){return x&-x;}
    inline void add(ll x){while(x<=n) ++f[x],x+=lowbit(x);return;}
    inline void query(ll x){while(x) ans+=f[x],x-=lowbit(x);return;}
    int main(){
        n=read();
        for(ll i=1;i<=n;++i) b[i]=read(),a[i]=i;
        stable_sort(a+1,a+1+n,cmp);
        for(ll i=1;i<=n;++i) add(a[i]),query(a[i]-1);
        printf("%lld",ans);
        return 0;
    }
    

    复杂度为(O(nlogn))


    推荐使用树状数组,毕竟树状数组能做的东西比归并排序多,但是两种方式都是必须要掌握的

    一些练习题:

    逆序对

    火柴排队

    LIT-Letters

    排序

    如果能把这些题目都写完了,那么您对逆序对一定掌握的非常熟练了

  • 相关阅读:
    hdu 1164 Eddy's research I
    hdu 3794 Magic Coupon
    hdu 1460 完数
    hdu 1201 18岁生日
    求一组整数中所有素数之和
    备忘录
    c判断括弧是否匹配
    N!大整数阶乘问题
    计算一个人从出生到现在活了多少天
    java web.xml配置详解(转)
  • 原文地址:https://www.cnblogs.com/RadestionAdtinium/p/13301267.html
Copyright © 2011-2022 走看看