zoukankan      html  css  js  c++  java
  • 一天一道算法题——逆序对(归并排序,树状数组,离散化)

    题目【逆序对】:https://www.luogu.com.cn/problem/P1908

    解法一:暴力法,适用于n比较小的时候,本题不适用。

    解法二:归并排序。

    我们很容易得出在合并操作的时候会找到逆序对。

    记i指向左边区域的当前节点,j指向右边区域的当前节点。

    当a[i]<=a[j]时,a[i]与右边区域的大于等于a[j]的所有数不构成逆序对,只需i++就好。

    当a[i]>a[j]时,a[j]与左区域的大于等于a[i]的所有数皆构成逆序对,所以逆序对数目+=mid-l+1

    因为int会溢出,所以sum用了long long

     1 #include<iostream>
     2 #include<stdio.h>
     3 #include<algorithm>
     4 #define N 500010
     5 using namespace std;
     6 
     7 int n, a[N],c[N];
     8 long long sum=0;
     9 void mergeSort(int l, int r) {
    10     if (l >= r)return;
    11     int mid = (l + r) >> 1,k = mid + 1, t = l, left = l, right = r;
    12     mergeSort(l, mid);
    13     mergeSort(mid + 1, r);
    14     while (l <= mid && k <= r) {
    15         if (a[l] <= a[k]) {
    16             c[t++] = a[l++];
    17         }
    18         else
    19             c[t++] = a[k++], sum += (long long)mid - l + 1;
    20     }
    21     while (l <= mid)
    22         c[t++] = a[l++];
    23     while (k <= r)
    24         c[t++] = a[k++];
    25     for (; left <= right; left++)
    26         a[left] = c[left];
    27 }
    28 
    29 int main() {
    30     scanf("%d", &n);
    31     for (int i = 1; i <= n; i++)
    32         scanf("%d", &a[i]);
    33     mergeSort(1, n);
    34     printf("%lld", sum);
    35     return 0;
    36 }

    ∠(°ゝ°)!

    解法三:树状数组

    记a[i]为原数组

    然后我们将每个a[i]在树状数组tree[]里对应的位置都+1,这样a[i]的前缀和就代表了比它小或相等的数,那么i-前缀和就是逆序对的数量了。

    接着……溢出了。

    因为序列中的每个数不超过10^9,所以,你懂的。

    为了减少空间消耗,我们采用离散化。

    将a排序,然后将每个数分别用1……n代替,这样tree只需要10^5<<2的大小,大大减少了消耗。

    代码如下:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<stdio.h>
     4 #define N 500010
     5 #define lowbit(x) x&-x
     6 typedef long long ll;
     7 using namespace std;
     8 
     9 int n, b[N],tree[N<<2];
    10 struct node {
    11     int val, num;
    12 } a[N];
    13 
    14 //inline作用和define差不多
    15 inline bool cmp(node a, node b) {
    16     if (a.val == b.val)return a.num < b.num;
    17     return a.val < b.val;
    18 }
    19 void insert(int x, int k) {
    20     while (x <= n) {
    21         tree[x] += k;
    22         x += lowbit(x);
    23     }
    24 }
    25 ll query(int x) {
    26     ll ans = 0;
    27     while (x) {
    28         ans += tree[x];
    29         x -= lowbit(x);
    30     }
    31     return ans;
    32 }
    33 
    34 int main() {
    35     scanf("%d", &n);
    36     for (int i = 1; i <= n; i++)
    37         scanf("%d", &a[i].val), a[i].num = i;
    38     //离散化,防止有些数太大,导出空间溢出
    39     sort(a + 1, a + n + 1, cmp);
    40     for (int i = 1; i <= n; i++)
    41         b[a[i].num] = i;
    42     ll ans=0;
    43     for (int i = 1; i <= n; i++) {
    44         insert(b[i], 1);
    45         ans += i-query(b[i]);
    46     }
    47     printf("%lld", ans);
    48     return 0;
    49 }
  • 相关阅读:
    Sum Root to Leaf Numbers
    Sum Root to Leaf Numbers
    Sort Colors
    Partition List
    Binary Tree Inorder Traversal
    Binary Tree Postorder Traversal
    Remove Duplicates from Sorted List II
    Remove Duplicates from Sorted List
    Search a 2D Matrix
    leetcode221
  • 原文地址:https://www.cnblogs.com/zyyz1126/p/12611742.html
Copyright © 2011-2022 走看看