Luogu_P3129

Luogu

算法

  • 贪心

思路

由于 Bessie 预先知道了 Elsie 的出牌策略, 所以可以贪心, 考虑每次都出比 Elsie 大一点点的牌, 如果没有就改变规则, 这样可以保证得分最大化.
\(f_i\) 表示每次都出大一点点的牌最多可以赢几次, \(g_i\) 相反.
则最后的答案为 \(max_{i}^{n} \{f_i + g_{i+1}\}\)
关于重复的证明见 Link

代码

#include <bits/stdc++.h>
  
using namespace std;

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
  
  int n;
  cin >> n;
  
  vector<int> Elsie(n);
  set<int, greater<int>> BessieG;
  set<int, less<int>> BessieL;
  vector<bool> used(2 * n + 1, false);
  
  for (int i = 0; i < n; i++) {
    cin >> Elsie[i];
  
    used[Elsie[i]] = true;
  }
  
  for (int i = 1; i <= 2 * n; i++) {
    if (used[i] == false) {
      BessieG.insert(i);
      BessieL.insert(i);
    }
  }
  
  vector<int> f(n + 2), g(n + 2);
  
  for (int i = 1; i <= n; i++) {
    set<int>::iterator found = BessieL.lower_bound(Elsie[i - 1]);
  
    // * 如果 found != BessieG.end(), 则 Bessie 可以在这一轮出比 Elsie 大的
    if (found != BessieL.end()) {
      BessieL.erase(found);
      f[i] = f[i - 1] + 1;
    } else {
      f[i] = f[i - 1];
    }
  }
  
  // ! 注意这里要逆序循环 (40 pts)
  for (int i = n; i >= 1; i--) {
    set<int>::iterator found = BessieG.lower_bound(Elsie[i - 1]);
  
    // * 如果 found != BessieL.end(), 则 Bessie 可以在这一轮出比 Elsie 小的
    if (found != BessieG.end()) {
      BessieG.erase(found);
      g[i] = g[i + 1] + 1;
    } else {
      g[i] = g[i + 1];
    }
  }
  
  int answer = 0;
  
  // ! 这里统计答案的范围为 [0, n] (47 pts)
  for (int i = 0; i <= n; i++) {
    answer = max(answer, f[i] + g[i + 1]);
  }
  
  cout << answer << '\n';
  
  return 0;
}
posted @ 2025-07-09 12:13  Fallen_Leaf  阅读(9)  评论(0)    收藏  举报