CSP-S 2021 廊桥分配
贪心
算法 1
考虑枚举所有可能,也就是 \((0, n), (1, n - 1), \dots, (n, 0)\),做法同弱化版相同。时间复杂度为 \(O(n^2 \log n)\)。(使用 std::priority_queue
实现)
算法 2
考虑优化。假设有 \(i\) 个廊桥,当我们求完后继续求 \(i + 1\) 时,前 \(i\) 个廊桥的使用是不变的。因此考虑第 \(i\) 个廊桥停了多少飞机,记作 \(f_i\),则所有廊桥能停的飞机数是 \(\sum f\)。
维护已使用的廊桥和未使用的廊桥的编号,每次处理已经走的飞机,并且加入当前飞机。
时间复杂度为 \(O(n \log n)\)。
#include <bits/stdc++.h>
const int N = 100005;
int n, m1, m2;
struct Node {
int l, r;
bool operator<(const Node &rhs) {
if (l == rhs.l)
return r < rhs.r;
return l < rhs.l;
}
} a[2][N];
int f[N], g[N];
void solve(int o) {
int m = o ? m2 : m1;
std::priority_queue<int> q1;
std::priority_queue<std::pair<int, int>> q2;
for (int i = 1; i <= n; i++) q1.push(-i);
for (int i = 1; i <= m; i++) {
while (!q2.empty()) {
std::pair<int, int> u = q2.top();
if (-u.first > a[o][i].l) break;
q1.push(-u.second), q2.pop();
}
if (!q1.empty()) {
int u = -q1.top(); q1.pop();
o ? g[u]++ : f[u]++;
q2.push({-a[o][i].r, u});
}
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n >> m1 >> m2;
for (int i = 1; i <= m1; i++) {
int x, y;
std::cin >> x >> y;
a[0][i] = {x, y};
}
for (int i = 1; i <= m2; i++) {
int x, y;
std::cin >> x >> y;
a[1][i] = {x, y};
}
std::sort(a[0] + 1, a[0] + 1 + m1);
std::sort(a[1] + 1, a[1] + 1 + m2);
solve(0), solve(1);
for (int i = 1; i <= n; i++) {
f[i] += f[i - 1];
g[i] += g[i - 1];
}
int ans = 0;
for (int i = 0; i <= n; i++)
ans = std::max(ans, f[i] + g[n - i]);
std::cout << ans << '\n';
return 0;
}