ARC 037 C - 億マス計算
ARC 037 C - 億マス計算 についてのメモを残します。
二分探索を 2 回使う
- 問題 : ARC 037 C - 億マス計算
マス計算で得られる 個の値を昇順に並べ、小さい方から 番目の値を出力する問題。
は最大 なので、 個のマスを 1 個ずつ埋めていく方法は TLE となる。
以下、典型的な解法として覚えておく。
小さい方から 番目の値を とする。このとき、次のことが言える。
- 以下であるマスは 個未満しか存在せず、 以下であるマスは 個以上存在する
よって、「 以下であるマスが 個以上存在する」を満たす最小の (これが ) を求めればよい。
が小さいほど 以下のマスの個数は少なく、 が大きいほど 以下のマスの個数は多くなるため、実装では、二分探索によって を求める。
では、 以下であるマスが 個以上存在するかどうかの判定はどうやるか。これも二分探索を用いる。
あらかじめ を昇順にソートして、 マス表を、どの行も右へいくほど値が大きくなるようにしておく。
以下の方法で 1 行ずつ 以下のマスの個数を数えて、合計の個数を求めるとよい。
- 行目について、 を満たす の個数を求める
のうち、要素が 以下である の個数は二分探索で求められる。
#include <bits/stdc++.h> using namespace std; int N, K; vector<long long> A, B; // x 以下であるマスが K 個以上あるかどうか判定 bool func(long long x) { int res = 0; // 1 行ずつ x 以下であるマスを数える for (int i = 0; i < N; i++) { long long tmp = x / A.at(i); // b_j <= [x / a_i] を満たす j の個数を加算 res += upper_bound(B.begin(), B.end(), tmp) - B.begin(); } return res >= K; } int main() { cin >> N >> K; A.resize(N); B.resize(N); for (int i = 0; i < N; i++) cin >> A.at(i); for (int i = 0; i < N; i++) cin >> B.at(i); sort(B.begin(), B.end()); // x 以下であるマスが K 個以上あるような最小の x を求める long long left = 0; long long right = 1LL << 60; while (right - left > 1) { long long mid = (left + right) / 2; if (func(mid)) right = mid; else left = mid; } cout << right << endl; }