題意:
給長度 n 的陣列,計數反轉對 (i < j 且 a[i] > a[j]) 的數量。
解題思路:
MergeSort 的合併階段同時計數跨段反轉數:當 left[i] > right[j],則 left[i..m] 都大於 right[j],一次加上 (m - i + 1)。
#include <bits/stdc++.h>
using namespace std;
long long merge_and_count(vector<long long>& a, vector<long long>& tmp, int l, int m, int r) {
int i = l, j = m + 1, k = l;
long long inv = 0;
while (i <= m && j <= r) {
if (a[i] <= a[j]) tmp[k++] = a[i++];
else {
tmp[k++] = a[j++];
inv += (m - i + 1);
}
}
while (i <= m) tmp[k++] = a[i++];
while (j <= r) tmp[k++] = a[j++];
for (int p = l; p <= r; ++p) a[p] = tmp[p];
return inv;
}
long long sort_and_count(vector<long long>& a, vector<long long>& tmp, int l, int r) {
if (l >= r) return 0;
int m = (l + r) >> 1;
long long inv = 0;
inv += sort_and_count(a, tmp, l, m);
inv += sort_and_count(a, tmp, m + 1, r);
inv += merge_and_count(a, tmp, l, m, r);
return inv;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<long long> a(n), tmp(n);
for (int i = 0; i < n; ++i) cin >> a[i];
long long ans = sort_and_count(a, tmp, 0, n - 1);
cout << ans << "\n";
return 0;
}
原題:
https://cses.fi/problemset/task/1661
題意:
長度 n 的整數陣列(可有負數),計算子陣列和等於 x 的個數。
解題思路:
前綴和 pref[j],想要 pref[j] - pref[i-1] = x,等價 pref[i-1] = pref[j] - x。
遍歷 pref[j],用 unordered_map<long long, long long> 存出現次數並累加答案。注意初始化 cnt[0] = 1(空前綴)。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n; long long x;
cin >> n >> x;
vector<long long> a(n);
for (int i = 0; i < n; ++i) cin >> a[i];
unordered_map<long long, long long> cnt;
cnt[0] = 1; // 空前綴
long long ans = 0, pref = 0;
for (int i = 0; i < n; ++i) {
pref += a[i];
long long need = pref - x;
auto it = cnt.find(need);
if (it != cnt.end()) ans += it->second;
++cnt[pref];
}
cout << ans << "\n";
return 0;
}
原題:
https://leetcode.com/problems/sort-colors/description/
題意:
陣列只含 0/1/2,請原地排序成 0...0 1...1 2...2。
解題思路:三指標 l, i, r:
nums[i]==0 → 與 nums[l] 交換,l++, i++
nums[i]==2 → 與 nums[r] 交換,r--(i 不動)
nums[i]==1 → i++
class Solution {
public:
void sortColors(vector<int>& nums) {
int l = 0, i = 0, r = (int)nums.size() - 1;
while (i <= r) {
if (nums[i] == 0) {
swap(nums[i++], nums[l++]);
} else if (nums[i] == 2) {
swap(nums[i], nums[r--]); // i 不前進
} else {
i++;
}
}
}
};
原題:
https://leetcode.com/problems/sort-an-array/description/
題意:
實作排序並回傳有序陣列。
思路:
用 MergeSort;需要 O(n) 暫存,但穩定且最壞仍 O(n log n)。
class Solution {
void mergeVec(vector<int>& a, vector<int>& tmp, int l, int m, int r) {
int i = l, j = m + 1, k = l;
while (i <= m && j <= r) {
if (a[i] <= a[j]) tmp[k++] = a[i++];
else tmp[k++] = a[j++];
}
while (i <= m) tmp[k++] = a[i++];
while (j <= r) tmp[k++] = a[j++];
for (int p = l; p <= r; ++p) a[p] = tmp[p];
}
void mergesort(vector<int>& a, vector<int>& tmp, int l, int r) {
if (l >= r) return;
int m = (l + r) >> 1;
mergesort(a, tmp, l, m);
mergesort(a, tmp, m + 1, r);
mergeVec(a, tmp, l, m, r);
}
public:
vector<int> sortArray(vector<int>& nums) {
vector<int> tmp(nums.size());
mergesort(nums, tmp, 0, (int)nums.size() - 1);
return nums;
}
};