题目描述
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。比如一个序列为4 5 1 3 2, 那么这个序列的逆序数为7,逆序对分别为(4, 1), (4, 3), (4, 2), (5, 1), (5, 3), (5, 2),(3, 2)。
输入描述:
第一行有一个整数n(1 <= n <= 100000), 然后第二行跟着n个整数,对于第i个数a[i],(0 <= a[i] <= 100000)。
输出描述:
输出这个序列中的逆序数
样例输入
5
4 5 1 3 2
样例输出
7
方法一:树状数组
import java.util.Scanner;
public class Main {
static final int MAX= (int) (1e5+10);
static int[] tree=new int[MAX];
static int n;
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
n=cin.nextInt();
long ans=0;
int temp;
for(int i=1;i<=n;i++){
temp=cin.nextInt();
add(temp,1);
ans+=i-sum(temp);
}
System.out.println(ans);
}
static int lowbit(int x){
return x&(-x);
}
static void add(int x,int d){
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
static int sum(int x){
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
}
方法二:二分(归并排序)
#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+10;
int Array[MAX];
long long cnt = 0;
void MergeSort(int Array[], int L, int R) {
if (L >= R)
return;
int Mid = (L + R) >> 1;
if (L < R) {
MergeSort(Array, L, Mid);//二分
MergeSort(Array, Mid + 1, R);//二分
}
int Temp[R - L + 1];
int i = L, j = Mid + 1, k = 0;
while (i <= Mid && j <= R) {
if (Array[i] > Array[j]) {
Temp[k++] = Array[j++];
cnt += Mid - i + 1;
} else {
Temp[k++] = Array[i++];
}
}
while (i <= Mid) {
Temp[k++] = Array[i++];
}
while (j <= R) {
Temp[k++] = Array[j++];
}
k = 0;
i = L;
while (i<=R)
Array[i++] = Temp[k++];
}
int main() {
int len;
cin >> len;
for (int i = 0; i < len; i++)
cin >> Array[i];
MergeSort(Array, 0, len - 1);
cout << cnt << endl;
return 0;
}