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;
}
posted @ 2024-10-07 17:24  Unino  阅读(5)  评论(0)    收藏  举报