1908 逆序对

1908 逆序对

难度:普及+/提高

题目类型:递归/分治

提交次数:1

涉及知识:归并排序

题目描述

猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。

代码:

#include<iostream>
using namespace std;
const int N = 100010;
int a[N];
int temp[N];
int ans;
void merge(int l, int m, int r){
    int i = l, k = l, j = m+1;
    while(i<=m&&j<=r){
        if(a[i]>a[j]){
            temp[k++] = a[j++];
            ans+=m-i+1;
        }
        else
            temp[k++] = a[i++];
    }
    while(i<=m) temp[k++] = a[i++];
    while(j<=r) temp[k++] = a[j++];
    for(i = l; i<=r; i++)
        a[i] = temp[i];
}
void merge_sort(int l, int r){
    if(l < r){
        int mid = (l + r)/2;
        merge_sort(l, mid);
        merge_sort(mid+1, r);
        merge(l, mid, r);
    }
}
int main(){
    int n, i;
    cin>>n;
    for(i = 1; i <= n; i++)
        cin>>a[i];
    merge_sort(1, n);
    cout<<ans<<endl;
    return 0;
} 

备注:

很经典的一道题,结课考试也考过,思路就是利用归并排序的特点,在merge中加入“关键的一行”。主要目的是巩固归并排序,看了半天终于背下来了,程序是自己写的,而且居然一遍就写对了∩_∩,看来记忆力还行(其实是因为把每一行代码都理解吃透了才记住。。),如果不多写写肯定又忘了。那关键的一行,第一次看的时候还看不明白,感觉那时候自己好傻(好吧现在也不怎么聪明),很简单嘛,分别排序的过程不能改变跨组的逆序对,merge的时候如果a[i]>a[j](按理说a[j]应该是比最后一个a[i]大的),a[j]这样一抢了先,有多少个a[i]会很难过呢?自然就是m-i+1个了!嗯,这么解释清楚不清楚?反正我觉得比较清楚。以后不懂的细节还是要花时间细细想想。

原文地址:https://www.cnblogs.com/fangziyuan/p/5784793.html