zoukankan      html  css  js  c++  java
  • 求排列的逆序数(分治)

    考虑1,2,…,n (n <= 100000)的排列i1,i2,…,in,如果其中存在j,k,满足 j < k 且 ij > ik, 那么就称(ij,ik)是这个排列的一个逆序。
    一个排列含有逆序的个数称为这个排列的逆序数。例如排列 263451 含有8个 逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此该排列的逆序数就是8。
    现给定1,2,…,n的一个排列,求它的逆序数。

    笨办法:O(n2)

    分治O(nlogn):
    1) 将数组分成两半,分别求出左半边的逆序数和右半边的逆序数
    2) 再算有多少逆序是由左半边取一个数和右半边取一个数构成(要求O(n)实 现)

    由归并排序改进得到,加上计算逆序的步骤

    MergeSortAndCount: 归并排序并计算逆序数

    代码:

    #include<iostream>
    using namespace std;
    #define N 100000 + 5
    int n; 
    int a[N];
    int b[N];
    int ans = 0;
    void merge(int L, int R) {
        int mid = (L + R) / 2;
        int l = L;
        int r = mid+1;
        int count = 0;
        while(l <= mid && r <= R) {
            if(a[l] < a[r]) {
                b[count++] = a[r++];    
            } else {
                b[count++] = a[l++];
                ans += R - r + 1;
            }
        }
        while(l <= mid) b[count++] = a[l++];
        while(r <= R) b[count++] = a[r++];
        for(int i = L; i <= R; i++) a[i] = b[i-L];
    }
    void MergeSortAndCount(int L, int R) {
        if(L < R) {
            int mid = (L + R) / 2;
            MergeSortAndCount(L, mid);
            MergeSortAndCount(mid + 1, R);
            merge(L, R);
        }
    }
    int main() {
        scanf("%d", &n);
        for(int i = 0; i < n; i++) scanf("%d", &a[i]);
        MergeSortAndCount(0, n-1);
        printf("%d
    ", ans);
        return 0;
    }
    作者:kindleheart
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    oracle补丁升级
    Vmware虚拟机设置静态IP地址
    VMware 虚拟机安装
    中国城市json
    安装vue
    中国省份城市数据
    ajax表单提交post(错误400) 序列化表单(post表单转换json(序列化))
    自动搭建ssm项目
    小米root
    程序员职业规划(一篇来自"阿里Java工程师"对工作3年左右程序员的职业建议和应该掌握的职业技能)
  • 原文地址:https://www.cnblogs.com/kindleheart/p/9416210.html
Copyright © 2011-2022 走看看