• AcWing 超快速排序


    每发现相邻数字顺序颠倒即将其交换,此时序列的逆序数减一.所以求出给定序列逆序和即可.

    求逆序和最简单的方法是冒泡排序,但是O(n2)是很不好的算法.

    常用的求逆序和方法有归并排序和树状数组,这里使用归并排序方法.实现见此模板.(假设数组下标从1开始)

    void merge(int l, int r){
        if(l == r) return;
        int mid = l + r >> 1;
        merge(l, mid);
        merge(mid + 1, r);
        int i = l, j = mid + 1;
        for(int k = l; k <= r; k++)
            if(j > r || i <= mid && s[i] < s[j]) tmp[k] = s[i++];    // 注意如果序列中有重复数字需要改为s[i] <= s[j]
            else tmp[k] = s[j++], ct += mid - i + 1;
        for(int k = l; k <= r; k++) s[k] = tmp[k];
    }

    执行该函数后,数组s将被按升序排列,且ct(假设初始化为0)的值即为原序列的逆序数.

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    long long s[500010], b[500010], n, ct;
    
    void merge(int l, int r){
        if(r <= l) return;
        int mid = l + r >> 1;
        merge(l, mid);
        merge(mid + 1, r);
        int i = l, j = mid + 1;
        for(int k = l; k <= r; k++)
            if(j > r || i <= mid && s[i] < s[j]) b[k] = s[i++];
            else b[k] = s[j++], ct += mid - i + 1;
        for(int i = l; i <= r; i++) s[i] = b[i];
    }
    
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0),cout.tie(0);
        while(cin >> n){
            if(!n) break;
            ct = 0;
            for(int i = 1; i <= n; i++) cin >> s[i];
            merge(1, n);
            cout << ct << endl;
        }
    
        return 0;
    }
    AC Code
  • 相关阅读:
    Java设计模式--命令模式
    linux 挂载windows盘
    C# 对含有向量偏移的明文进行AES加解密
    Vue修仙之旅之Vue初尝
    Cookie的Secure属性
    Webserver信息泄露的解决方案--使用StripHeaders模块删除不必要的header
    window自定义事件
    vue typescript .eslintrc.js
    css word-break: break-word;无效
    vscode vue 片段
  • 原文地址:https://www.cnblogs.com/Gaomez/p/14167585.html
Copyright © 2020-2023  润新知