ferinの競プロ帳

競プロについてのメモ

SRM657 div1 easy ProblemSets

考えたこと

  • EMでEとして使う問題数をw、Mとして使う問題数をx、MHでMとして使う問題をy、Hとして使う問題数をzとする
  • min(E+w, M+x+y, H+z)を最大化すればよい
  • 最小の最大化はにぶたんをしたくなる
  • 問題セットの数cntを作れるかの判定をしたい
  • Eがcntより小さければEMからその分Eに使うしかない、Hについても同様
  • EとHに使わないといけない問題を使ったあとMに使える問題数がcnt以上ならcnt個はつくれる
  • O(1)で判定ができるので二分探索ができた

二分探索がすんなり思いついてよかった

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef vector<VL> VVL;
typedef pair<int, int> PII;

#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)
#define REP(i, n) FOR(i, 0, n)
#define ALL(x) x.begin(), x.end()
#define IN(a, b, x) (a<=x&&x<b)
#define MP make_pair
#define PB push_back
const int INF = (1LL<<30);
const ll LLINF = (1LL<<60);
const double PI = 3.14159265359;
const double EPS = 1e-12;
const int MOD = 1000000007;
//#define int ll

template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); }

int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};

class ProblemSets {
   public:
   long long maxSets(long long E, long long EM, long long M, long long MH, long long H)
  {
    ll lb = 0, ub = 2e18;

    auto check = [&](ll mid) -> bool {
      ll a = E, b = EM, c = M, d = MH, e = H;
      if(a < mid) {
        if(b < mid-a) return false;
        b -= mid - a;
        a = mid;
      }
      if(e < mid) {
        if(d < mid-e) return false;
        d -= mid-e;
        e = mid;
      }
      return b+c+d >= mid;
    };

    while(ub-lb > 1) {
      ll mid = (lb+ub)/2;
      // cout << lb << " " << mid << " " << ub << endl;
      if(check(mid)) {
        lb = mid;
      } else {
        ub = mid;
      }
    }

    return lb;
  }
};