787 归并排序基础

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 100010;
  4. int temp[N],a[N],n;
  5. void merge_sort(int a[], int l, int r){
  6. if(l >= r)return;
  7. int mid = (l + r) >> 1;
  8. merge_sort(a, l, mid);
  9. merge_sort(a, mid + 1, r);
  10. int k = 0, i = l, j = mid + 1;
  11. while (i <= mid && j <= r){
  12. if(a[i] < a[j]) temp[k++] = a[i++];
  13. else temp[k++] = a[j++];
  14. }
  15. while (i <= mid) temp[k++] = a[i++];
  16. while (j <= r) temp[k++] = a[j++];
  17. k = 0;
  18. for(int i = l; i<=r; i++ ) a[i]=temp[k++];
  19. }
  20. int main (){
  21. scanf("%d", &n);
  22. for(int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
  23. merge_sort(a, 0, n-1);
  24. for(int i = 0; i < n; i++ )printf("%d ",a[i]);
  25. return 0;
  26. }

788 逆序对的数量

image.png
地址:https://www.acwing.com/problem/content/790/

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 100010;
  4. int temp[N];
  5. int a[N],n;
  6. long long reverseNum( int l, int r){
  7. //在归并排序的过程中,计算逆序对
  8. if(l >= r) return 0;
  9. int mid = l + r >> 1;
  10. long long num = reverseNum(l, mid) + reverseNum(mid + 1, r);//
  11. int k=0, i = l, j = mid + 1;
  12. while(i <= mid && j <= r){
  13. if(a[i] <= a[j]){//在该步骤判断是否逆序
  14. temp[k++] = a[i++];
  15. }else{
  16. temp[k++] = a[j++];
  17. num += mid - i + 1;
  18. }
  19. }
  20. while(i <= mid) temp[k++] = a[i++];
  21. while(j <= r) temp[k++] = a[j++];
  22. for(int i = l,k = 0; i <= r; i++, k++)a[i]=temp[k];
  23. return num;
  24. }
  25. int main(){
  26. cin >> n;
  27. for(int i = 0; i < n; i++ ) cin >> a[i];
  28. cout << reverseNum(0, n-1) << endl;
  29. return 0;
  30. }

分析

归并算法的基本思想 左右两组进行对比,即分治算法。在每次循环的时候,左右两组均为有序。自底向上,最底层的两组,即两个数字m和n,左右两组各有一个数字,这自然是有序的。自此由下往上,使用归并算法,使得每组均有序。
在求逆序数的过程中,我们只需关注,左右两组的数字作比较,即左边的某一个数字a[i]开始大于右边的a[j],此时i到mid均大于j。

总结

思想简单,但理解起来略有难度,比较绕