题目大意:
给你一个上限为(5e5)的整数 n 。
在给出 n 个非负整数,这些数上限是 999 999 999 。
求出其中有多少个逆序数对。
解释下逆序数对:
比如在数列 1 ,2 ,5 ,4 ,3 中,
1 的逆序数就是后面所有比它小的数字个数,即为 0 。
2 同理 ,即为 0 。
5 后面有 3 和 4 ,即为 2 。
4 后面有一个 3 ,即为 1 。
3 后面没有数字,即为 0 。
所以在上述数列中,逆序数对有 0 + 0 + 2 + 1 + 0 == 3 个。
解题思路:
在归并的过程中检测单向移动距离之和(所谓单向 就是要么都计算往前移动的距离,要么相反,计算往后移动的距离)。
比如 3 ,2 ,4 ,1 。(检查数字向前移动的距离和)
第一步:3 和 2 调换 ,检查 3 向前移动了 1 个单位,数列变成: 2 3 4 1
第二步:4 和 1 调换 ,检查 4 向前移动了 1 个单位 ,数列变成: 2 3 1 4
第三步:归并两个子数列 ,发现只有 1 向前移动了两个单位,而后再也不出现向前移动的数字,数列也变成最终的有序数列。
如果计算向后移动的距离和也是同理:
3 移动 1 个单位 , 4 移动 1 个单位 , 2 移动 1 个单位 , 3 又移动 1 个单位。
加起来也是正好 4 个单位。
所以这个数列的逆序数对就是 4 ,输出换行即可。
AC代码:
1 import java.util.*; 2 3 public class Main{ 4 5 static long ans = 0L; 6 static int num[] = new int[500005]; 7 static int temp[] = new int[500005]; 8 9 static void merge(int low,int mid,int high){ 10 int i = low; int j = mid + 1; int k = low; 11 while(i <= mid && j <= high){ 12 if (num[i] <= num[j]){ 13 temp[k ++] = num[i ++]; 14 } 15 else{ 16 ans = ans + j - k ; 17 temp[k ++] = num[j ++]; 18 } 19 } 20 while (i <= mid) {temp[k ++] = num[i ++];} 21 while (j <= high){temp[k ++] = num[j ++];} 22 for(i = low; i <= high; ++i){ 23 num[i] = temp[i]; 24 } 25 } 26 27 static void sort(int a,int b){ 28 if(a < b){ 29 int mid = (a + b) / 2; 30 sort(a, mid); 31 sort(mid + 1, b); 32 merge(a, mid, b); 33 } 34 } 35 36 public static void main(String[] args){ 37 Scanner sc = new Scanner(System.in); 38 while(sc.hasNext()){ 39 int n = sc.nextInt(); 40 if(n == 0){break;} 41 for(int i = 0;i < n;i ++){ 42 num[i] = sc.nextInt(); 43 } 44 sort(0,n - 1); 45 System.out.println(ans); 46 ans = 0L; 47 } 48 } 49 }
此处再给出一个超时的代码,不过这个程序可以查看计算过程和排序过程,具体超时原因应该是出现了无用遍历。
超时代码:
1 import java.util.*; 2 3 public class Main{ 4 5 static int ans = 0; 6 7 static void print(int x[]){ 8 for(int i = 0; i < x.length; i++){ 9 System.out.print(x[i] + " "); 10 }System.out.println(); 11 } 12 13 static void mergeSort(int x[]){ 14 sort(x,0,x.length - 1); 15 } 16 17 18 static void sort(int arr[], int left, int right){ 19 if (left >= right){return; } 20 int mid = (left + right) / 2; 21 sort(arr, left, mid); 22 sort(arr, mid + 1, right); 23 merge(arr, left, mid, right); 24 //print(data); 25 } 26 27 static void merge(int Array[], int index_L, int index_C, int index_R){ 28 int Array_t[] = new int[Array.length]; 29 int mid = index_C + 1; 30 int index_t = index_L; 31 int _t = index_L; 32 while (index_L <= index_C && mid <= index_R){ 33 if (Array[index_L] <= Array[mid]){ 34 Array_t[index_t ++] = Array[index_L ++]; 35 } 36 else{ 37 //System.out.println(mid - index_t); 38 ans = ans + mid - index_t; 39 //System.out.println("ans " + ans); 40 Array_t[index_t ++] = Array[mid ++]; 41 } 42 } 43 while (mid <= index_R) { 44 Array_t[index_t ++] = Array[mid ++]; 45 } 46 while (index_L <= index_C) { 47 Array_t[index_t ++] = Array[index_L ++]; 48 } 49 while (_t <= index_R) { 50 Array[_t] = Array_t[_t ++]; 51 } 52 } 53 54 public static void main(String[] args){ 55 Scanner sc = new Scanner(System.in); 56 while(sc.hasNext()){ 57 int n = sc.nextInt(); 58 if(n == 0){break;} 59 int in[] = new int[n]; 60 for(int i = 0;i < n;i ++){ 61 in[i] = sc.nextInt(); 62 } 63 //print(in); 64 mergeSort(in); 65 //print(in); 66 System.out.println(ans); 67 ans = 0; 68 } 69 } 70 }