競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 312F

ABC312F

3つタイプがあるが,いずれも貪欲に取れる. どれか一つを全探索しよう. 缶切りを使わない缶全体, 缶切りを使う缶全体, 缶切り全体 をそれぞれ \(a,b,c\) とおく. \(a,b,c\) を全てソートしておく.

\(a\) を全探索する. \(i \in size(a)\) に対して,\([0,i)\) まで使ったとする. このとき,\(b,c\) からどちらを選ぶべきかは貪欲に決まる.
缶切りが残っていれば \(b\) から買えばよい. 残ってなければ,\(c\) から買って缶切りを補充. 実装するときは,\(b,c\) が空になる場合に注意.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll n, m ;
  cin >> n >> m;
  vvll a(3);
  rep(i,n){
    ll t, x; cin >> t >> x;
    a[t].push_back(x);
  }
  sort(all(a[0]), greater<ll>());
  sort(all(a[1]));
  sort(all(a[2]));


  vvll s(2, vll(n+1));
 
  ll r = 0;
  rep(i,n) {
    if(i < a[0].size()) s[0][i+1] = s[0][i] + a[0][i];
    else s[0][i+1] = s[0][i];

    ll now = 0;
    if(r){
      --r;
      if(a[1].size()){
        now = a[1].back();
        a[1].pop_back();
      }

    }else if(a[2].size()){
      r += a[2].back();
      a[2].pop_back();
    }
    s[1][i+1] = s[1][i] + now;
  }
 
  ll ans = -INFL;
  rep(i,m+1) chmax(ans, s[0][i] + s[1][m-i]);
  cout << ans << endl;


  return 0;
}