Hướng giải của Đếm số cặp nghịch thế
Nhớ rằng hướng dẫn giải này chỉ nên sử dụng khi bế tắc, và tuyệt đối không nên sao chép mã nguồn kèm theo. Hãy tôn trọng tác giả bài tập và người viết hướng dẫn giải.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.
Tác giả:
Để đếm số cặp nghịch thế hiệu quả trong \(O(N \log N)\), ta có thể cải tiến thuật toán Sắp xếp trộn (Merge Sort):
- Khi chia đôi mảng thành hai mảng con
L(bên trái) vàR(bên phải) đã được sắp xếp tăng dần. - Trong quá trình trộn hai mảng con lại với nhau:
- Nếu phần tử hiện tại của
Lnhỏ hơn hoặc bằng phần tử hiện tại củaR, ta đưa phần tử củaLvào mảng kết quả. - Nếu phần tử hiện tại
R[j]nhỏ hơn phần tử hiện tạiL[i], điều này có nghĩa là mọi phần tử từL[i]đến cuối mảng con trái đều lớn hơnR[j]. Do đó, số lượng cặp nghịch thế được đóng góp bởiR[j]chính là số phần tử còn lại trong mảng con tráiL(tức làmid - i + 1). Ta cộng thêm số lượng này vào kết quả.
- Nếu phần tử hiện tại của
Độ phức tạp thời gian: \(O(N \log N)\).
Xem code mẫu C++
#include <iostream>
#include <vector>
using namespace std;
long long merge_and_count(vector<long long>& a, int left, int mid, int right) {
vector<long long> temp(right - left + 1);
int i = left, j = mid + 1, k = 0;
long long count = 0;
while (i <= mid && j <= right) {
if (a[i] <= a[j]) {
temp[k++] = a[i++];
} else {
temp[k++] = a[j++];
count += (mid - i + 1);
}
}
while (i <= mid) temp[k++] = a[i++];
while (j <= right) temp[k++] = a[j++];
for (int p = 0; p < k; ++p) {
a[left + p] = temp[p];
}
return count;
}
long long merge_sort_and_count(vector<long long>& a, int left, int right) {
if (left >= right) return 0;
int mid = left + (right - left) / 2;
long long count = 0;
count += merge_sort_and_count(a, left, mid);
count += merge_sort_and_count(a, mid + 1, right);
count += merge_and_count(a, left, mid, right);
return count;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
if (!(cin >> n)) return 0;
vector<long long> a(n);
for (int i = 0; i < n; ++i) cin >> a[i];
long long ans = merge_sort_and_count(a, 0, n - 1);
cout << ans << "\n";
return 0;
}
Nhận xét