けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 083 C - Multiple Gift (5Q, 灰色, 300 点)

初歩的な Greedy の問題と言える。

問題概要

 X 以上  Y 以下の整数からなる数列  A_{1}, A_{2}, \dots であって、

  •  A_{i+1} \gt A_{i}
  •  A_{i+1} A_{i} で割り切れる

という条件を満たすものを考える。そのような数列の長さの最大値を求めよ。

制約

  •  1 \le X \le Y \le 10^{18}

考えたこと

基本的には、なるべく小さい値でスタートして、その次の値もなるべく小さくして、さらにその次の値もなるべく小さくして......というように考えれば良い。

そうすると、まず初項は

  •  A_{1} = X

とすればよい。二項目については、 A_{1} よりも大きくて、 A_{1} を割り切る最小の整数を持ってくればよい。それは、 2X である。よって、

  •  A_{2} = 2X

とすればよい。一般に、 A_{i} が決まっているとき、

  •  A_{i+1} = 2A_{i}

とすればよい。こうして、 Y を超えるまで続けていけばよい。

毎回 2 倍になっていくことから、 \log_{2}10^{18} 60 回程度で超えてしまうことがわかる。よって、愚直に 2 倍し続けても、計算時間には余裕がある。計算量をランダウの  O 記法で表すと、 O(\log Y) とかける。

コード

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

int main() {
    long long X, Y;
    cin >> X >> Y;

    int res = 0;
    long long num = X;

    // 値が Y を超えるまで 2 倍し続ける
    while (num <= Y) {
        res++;  // カウントする
        num *= 2;
    }
    cout << res << endl;
}