问题描述
SORT公司是一个专门提供排序服务的公司,该公司的宗旨是:“顺序是美丽的”。他们的工作是通过一系列移动,将某些物品按顺序摆好。他们的服务是通过工作量来计算的,即移动物品的次数。所以,在工作前必须先考察工作量,以便向客户提出收费数目。
用户并不需要知道精确的移动次数,实质上,大多数人都是凭感觉来认定这一列物品的混乱程度。根据SORT公司的经验,人们一般是根据“逆序对”的数目多少来称呼这一序列的混乱程度。假设将序列中第I件物品的参数定义为Ai,那么排序就是将A1,……An从小到大排序。若i<j且Ai>Aj,则<i,j>就为一个“逆序对".
SORT公司请你写一个程序,在尽量短的时间内统计出”逆序对“的数目。
输入格式
第1行为n(1<=n<=100000)
接下来N行,每行一个长整数型范围内的整数。
输出格式
一个整数,为逆序对的数目。
样例输入
5
3
1
4
5
2
样例输出
4
解题思路:
求逆序对的个数,如果仅仅用两层for循环暴力求解肯定会超时,可以利用归并排序的思想,在排序的过程中将逆序对的个数统计出来。
比如,当归并到【(2,4,7)(1,5,6)】时,对于右边的1,左边的三个数都是符合条件的逆序对,所以只需满足:当归并时,右边的数字小于左边的数字,则左边的这一数字之后的数字都满足条件,做累加。
另外,当数组为降序时,逆序对为n*(n - 1)/ 2。n最大可以取到10w,所以最后输出的数字应为long型。
归并排序算法见:
归并排序https://blog.csdn.net/weixin_48898946/article/details/122568427
java代码:
import java.io.*;
public class Main {
public static void main(String[] args) throws NumberFormatException, IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int []arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(br.readLine());
}
Merge test = new Merge(arr);
test.divide(0, arr.length - 1);
System.out.println(test.ans);
}
}
class Merge{
int []arr;
int []temp;
int ans = 0;
public Merge(int[] arr) {
this.arr = arr;
temp = new int[arr.length];
}
public void divide(int start, int end) {
if(start < end) {
int mid = (start + end) / 2;
divide(start, mid);
divide(mid + 1, end);
merge(start, mid, end);
}
}
public void merge(int start, int mid, int end) {
int i = start;
int j = mid + 1;
int index = 0;
while(i <= mid && j <= end) {
if(arr[i] <= arr[j]) {
temp[index++] = arr[i];
i++;
}else {
temp[index++] = arr[j];
j++;
ans += mid - i + 1;
}
}
while(i <= mid) {
temp[index++] = arr[i];
i++;
}
while(j <= end) {
temp[index++] = arr[j];
j++;
}
index = 0;
for(i = start; i <= end; i++) {
arr[i] = temp[index++];
}
}
}