题目情境#
题目链接:https://www.luogu.com.cn/problem/P1908 ↗
题目描述
猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。
最近,TOM 老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 且 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。
输入格式
第一行,一个数 ,表示序列中有 个数。
第二行 个数,表示给定的序列。序列中每个数字不超过 。
输出格式
输出序列中逆序对的数目。
输入输出样例
输入 #1
6
5 4 2 6 3 1
plaintext输出 #1
11plaintext说明/提示
对于所有数据,。
算法解析#
归并排序
主要利用分治思想,时间复杂度
- 对数列不断等长拆分,直到一个数的长度。
- 回溯时,按升序合并左右两段。
- 重复以上两个过程,直到递归结束。
Python代码实现#
import sys
sys.setrecursionlimit(1000000)
def merge(l, r):
global res, a, b
if l >= r:
return
mid = (l + r) // 2
merge(l, mid)
merge(mid + 1, r)
i = l; j = mid + 1; k = l
while i <= mid and j <= r:
if a[i] <= a[j]:
b[k] = a[i]
k += 1; i += 1
else:
b[k] = a[j]
k += 1; j += 1
res += mid - i + 1
while i <= mid:
b[k] = a[i]
k += 1; i += 1
while j <= r:
b[k] = a[j]
k += 1; j += 1
for i in range(l, r + 1):
a[i] = b[i]
n = int(input())
a = list(map(int, input().split()))
b = [0] * n
res = 0
merge(0, n - 1)
print(res)pythonC++代码实现#
#include <iostream>
using namespace std;
int n,a[500010],b[500010];
long long res;
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,k=l; //合并
while(i<=mid && j<=r){
if(a[i]<=a[j]) b[k++]=a[i++];
else b[k++]=a[j++], res+=mid-i+1;
}
while(i<=mid) b[k++]=a[i++];
while(j<=r) b[k++]=a[j++];
for(i=l; i<=r; i++) a[i]=b[i];
}
int main(){
cin>>n;
for(int i=0;i<n;i++) scanf("%d",&a[i]);
merge(0,n-1);
printf("%lld\n",res);
}c