fork download
  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4.  
  5. // Hàm này thực hiện merge hai mảng con đã được sắp xếp là arr[l..m] và arr[m+1..r]
  6. // Đồng thời đếm số nghịch thế trong mảng con arr[l..r]
  7. int countAndMerge(vector<int>& arr, int l, int m, int r) {
  8. // Số phần tử trong mảng trái và mảng phải
  9. int n1 = m - l + 1, n2 = r - m;
  10.  
  11. // Tạo hai mảng con lưu trữ giá trị từ mảng chính
  12. vector<int> left(n1), right(n2);
  13. for (int i = 0; i < n1; i++)
  14. left[i] = arr[i + l]; // Lấy giá trị từ phần mảng trái
  15. for (int j = 0; j < n2; j++)
  16. right[j] = arr[m + 1 + j]; // Lấy giá trị từ phần mảng phải
  17.  
  18. // Biến đếm số nghịch thế
  19. int res = 0;
  20.  
  21. // Các chỉ số để duyệt qua mảng trái, mảng phải và mảng chính
  22. int i = 0, j = 0, k = l;
  23.  
  24. // Thực hiện merge hai mảng con
  25. while (i < n1 && j < n2) {
  26. // Nếu phần tử bên trái nhỏ hơn hoặc bằng phần tử bên phải
  27. if (left[i] <= right[j]) {
  28. arr[k++] = left[i++]; // Gán phần tử bên trái vào mảng chính
  29. } else {
  30. // Nếu phần tử bên phải nhỏ hơn
  31. arr[k++] = right[j++];
  32. // Tăng số nghịch thế. Vì left[i] > right[j], nên tất cả phần tử từ left[i] đến left[n1-1]
  33. // đều tạo thành nghịch thế với right[j].
  34. res += (n1 - i);
  35. }
  36. }
  37.  
  38. // Thêm các phần tử còn lại của mảng trái (nếu có)
  39. while (i < n1)
  40. arr[k++] = left[i++];
  41.  
  42. // Thêm các phần tử còn lại của mảng phải (nếu có)
  43. while (j < n2)
  44. arr[k++] = right[j++];
  45.  
  46. return res; // Trả về số nghịch thế đã đếm
  47. }
  48.  
  49. // Hàm đệ quy để đếm số nghịch thế trong mảng
  50. int countInv(vector<int>& arr, int l, int r) {
  51. int res = 0; // Biến lưu số nghịch thế
  52. if (l < r) {
  53. // Tìm vị trí giữa để chia mảng thành hai nửa
  54. int m = (r + l) / 2;
  55.  
  56. // Đệ quy đếm nghịch thế ở nửa bên trái
  57. res += countInv(arr, l, m);
  58.  
  59. // Đệ quy đếm nghịch thế ở nửa bên phải
  60. res += countInv(arr, m + 1, r);
  61.  
  62. // Đếm nghịch thế trong quá trình merge hai nửa
  63. res += countAndMerge(arr, l, m, r);
  64. }
  65. return res; // Trả về tổng số nghịch thế
  66. }
  67.  
  68. // Hàm tổng quát để đếm nghịch thế trong mảng
  69. int inversionCount(vector<int> &arr) {
  70. int n = arr.size(); // Kích thước mảng
  71. return countInv(arr, 0, n - 1); // Gọi hàm đệ quy
  72. }
  73.  
  74. int main() {
  75. int n;
  76. cin >> n;
  77. vector<int> arr(n);
  78. for (int i = 0; i < n; i++) {
  79. cin >> arr[i];
  80. }
  81. // In ra kết quả là số lượng nghịch thế
  82. cout << "Number of inversions (O(n log n)): " << inversionCount(arr) << endl;
  83. return 0;
  84. }
Success #stdin #stdout 0s 5288KB
stdin
6
1 2 4 3 5 1
stdout
Number of inversions (O(n log n)): 5