码迷,mamicode.com
首页 > 其他好文 > 详细

逆序对的两种求法(复习)

时间:2018-10-18 18:08:02      阅读:130      评论:0      收藏:0      [点我收藏+]

标签:位置   bool   复杂   std   关系   回顾   ges   截取   merge   

逆序对

对于一个数列\(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})+O(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\n", ans);
    return 0;
} 

逆序对的两种求法(复习)

标签:位置   bool   复杂   std   关系   回顾   ges   截取   merge   

原文地址:https://www.cnblogs.com/water-mi/p/9811731.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!