zoukankan      html  css  js  c++  java
  • 逆序对的两种求法(复习)

    逆序对

    对于一个数列$a_1...a_n$,定义一有序对$(i,j)$当且仅当$i<j$且$a_i>a_j$为逆序对。接着我们来考虑怎么求

    *1. 归并排序

    回顾归并排序的过程,将当且的数列$[l,r]$分成两个长度相等的部分$[l,mid]$和$[mid+1,r]$,分治下去排序,每次合并的代价是区间的长度,所以得到时间复杂度为:
    $$
    T(n)=2T(frac{n}{2})+f(n)
    $$
    根据$master$定理可知时间复杂度为$Theta(nlog_2n)$

    int MergeSort (int l, int r) {
        if (l == r) return ;
        int mid = (l + r) >> 1;
        MergeSort(l, mid), MergeSort(mid + 1, r);
        int i = l, j = mid + 1, t = l;
        while(i <= mid && j <= r)
            if (a[i] <= a[j]) b[t++] = a[i++];
        	else b[t++] = a[j++];
        while(i <= mid) b[t++] = a[i++]; while(j <= r) b[t++] = a[j++];
        for(int k = l; k <= r; ++k) a[k] = b[k];
    }
    

    等一下!你讲了这么久,到底怎么求逆序对???


    我们截取一段代码:

    else b[t++] = a[j++]
    

    由于归并排序是将一个区间分成左右两端,故右边一段中的任何一个元素一定在左边一段中任何一个元素之后,这种性质同样用于分治处理,所以,当我们加入一个右区间元素时,此时左区间中剩下没加入的元素一定就比它大,所以改写一下:

    else b[t++] = a[j++], ans += mid - i + 1;//ans为逆序对个数
    

    由于分治的性质,所以每个逆序对都会不重不漏地选到。

    *2. 树状数组

    $BIT$作为一种巧妙的数据结构,其利用了一种类似于前缀和的思想。通过权值$BIT$来求解逆序对。

    其算法核心在于,先确立$a_j<a_i$的大小关系,按从小到大插入其下标,通过计算前缀和的方式来求解。

    比如我们现在有一个数$a_i$,我们向$BIT$中插入其下标$i$后计算当前小于等于其下标的数的个数$tot$,则答案就是$i-tot$。

    因为此时$a_i>a_j$($j$为之前已插入的数的下标),所以$i-tot$即位置在$i$之后的个数就是当前$i$ 对答案产生的贡献(满足$a_j<a_i&j>i$)。

    #include <cstdio>
    #include <algorithm>
    typedef long long ll;
    using std::sort;
    
    const ll N = 5e5 + 10;
    ll n, a[N], b[N], c[N], ans;
    
    inline bool cmp (ll x, ll y) { return a[x] < a[y] || (a[x] == a[y] && x < y); }
    inline ll lowbit (ll x) { return x & (-x); }
    inline void add (ll x, ll y) { for (; x <= n; x += lowbit(x)) c[x] += y; }
    inline ll query (ll x) { ll y = 0; for (; x > 0; x -= lowbit(x)) y += c[x]; return y; }
    
    int main () {
        scanf ("%lld", &n);
        for (ll i = 1; i <= n; ++i) scanf ("%lld", a + i), b[i] = i;
        sort (b + 1, b + n + 1, cmp);
        for (ll i = 1; i <= n; ++i) add(b[i], 1). ans += i - query (b[i]);
        printf ("%lld
    ", ans);
        return 0;
    } 
    
  • 相关阅读:
    (4)ES6解构赋值-字符串篇
    (3)ES6解构赋值-对象篇
    (2)ES6解构赋值-数组篇
    (1)ES6中let,const,对象冻结,跨模块常量,新增的全局对象介绍
    MySQL中char与varchar区别,varchar最大长度是多少?
    集成学习实战——Boosting(GBDT,Adaboost,XGBoost)
    集成学习——Boosting(GBDT,Adaboost,XGBoost)
    集成学习(Random Forest)——实践
    集成学习——Bagging
    决策树实践
  • 原文地址:https://www.cnblogs.com/water-mi/p/9811731.html
Copyright © 2011-2022 走看看