zoukankan      html  css  js  c++  java
  • 求逆序对的三种方法

    逆序对

    在数组A[x]中,若存在(i < j) && (A[i] > A[j]),则称(A[i],A[j])为数组A[x]的一个逆序对


    暴力O(N^2)求法

        for(i = 1; i <= n; i ++)
            for(j = i; j <= n; j ++)
                if(A[i] > A[j])cnt ++;
    

    归并排序求法

    由上面的表述可知,逆序对同样可以表示为:在数组A[x]中,若存在(i > j) && (A[i] < A[j]),则称(A[i],A[j])为数组A[x]的一个逆序对
    那么,设cnt[i]为A[i]前比它大的数字个数,逆序对数则 = cnt[1] + cnt[2] + cnt[3] + ... + cnt[n];
    一只总逆序对数为每个数字前比它大的数字个数之和,那么我们只需要在归并排序中统计这个数字个数即可

    #include<iostream>
    ...
    void merge(int L, int R, int Mid){
        int i = L;int j = Mid + 1;int k = L;
        while(i <= Mid && j <= R){
            if(s1[i] <= s1[j])s2[k ++] = s1[i ++];
            else{
                cnt += Mid - i + 1;
                //对于i到Mid这Mid - i + 1个数字(假设它为j),每一个a[j]都与a[i]构成了一个逆序对
                s2[k ++] = s1[j ++]; 
            }
        }
        while(i <= Mid)s2[k ++] = s1[i ++];
        //对于每个j都已讨论完,每个j钱比他大的数都已计入cnt,所以此时不用更新cnt
        while(j <= R)s2[k ++] = s1[j ++];
        for(i = L; i <= R; i ++)s1[i] = s2[i]; 
    }
    void mergesort(int L, int R){
        if(L < R){
            int Mid = (L + R) / 2;
            mergesort(L, Mid),mergesort(Mid + 1, R);
            merge(L, R, Mid);
        }
    }
    int main(){
    	scanf("%d", &n);
    	for(int i = 1; i <= n; i ++)scanf("%d", &s1[i]);
    	mergesort(1, n);
    	for(int i = 1; i <= n; i ++)printf("%d", s1[i]);
    }
    

    树状数组求逆序对

    虚拟一个数组A[i],A[i] == 1表示出现了i,A[i] == 0表示没有出现i
    利用树状数组,getsum(i)表示i~i中出现的数字个数
    边输入边进行操作,对于当前的数字x,它所贡献的逆序对书即为在它之前出现的比它大的数字的总数,即为当前x~n的sum值->getsum(n)-getsum(x);之后再将A[i] ++,更新C[i](modify)

    #include<iostream>
    #define lowbit(x) x & -x
    ...
    void modify(int x, int d){
    	for(int i = x; i <= n; i += lowbit(i))c[i] += d;
    }
    int getsum(int x){
    	int sum = 0;
    	for(int i = x; i >= 1; i -= lowbit(i))sum += c[i];
    	return sum;
    }
    int main(){
    	scanf("%d", &n);
    	for(int i = 1; i <= n; i ++){
    		scanf("%d", &x);
    		ans += getsum(n) - getsum(x);
    		modify(x, 1)''
    	}
    }
    
  • 相关阅读:
    51Nod1528 加号分配
    51Nod1679 连通率
    51Nod1679 连通率
    51Nod1426 沙拉酱括号
    51Nod1426 沙拉酱括号
    51Nod1678 lky与gcd
    51Nod1556 计算
    c学习第2天
    Stopwatch秒表的使用
    数据从.txt文件中导入数据库
  • 原文地址:https://www.cnblogs.com/qwqq/p/11059365.html
Copyright © 2011-2022 走看看