貪欲法 atcoder 数列

ABC083 C - Multiple Gift

ABC083 C - Multiple Gift
Feb. 2, 2020, 1:52 p.m.

目次

問題

https://atcoder.jp/contests/abc083/tasks/arc088_a

$1 \leq X \leq Y \leq 10^{18}$を満たす2つの整数$X, Y$が与えられます.
要素がX以上Y以下(①)で、かつ前の要素の倍数で(②)前の要素よりも大きい(③)数列$A$の最大長を求める問題です.

  • $X \leq A_i \leq Y$ - ①
  • $A_{i+1} = k A_i$ - ②
  • $A_i < A_{i+1}$ - ③

入力

X Y

出力

N

入出力例

3 20
3

数列$A = 3, 6, 18$となり長さは$3$です.

解説

次の要素は必ず倍数になっていてより大きい数です.
倍数は無数にありますが、目的は数列の長さを長くすることなのでその中でも一番小さい要素を次の要素とするのが良いです.
後ろにより多くの要素を詰めることが出来るからです.

一番小さい倍数は2倍したものです.
$X$が一番小さい要素なので、$X$から開始して$Y$を超えるまで何回2倍することが出来るかをカウントすれば答えが求まります.

$$
A = X, 2X, 4X, 8X, 16X, ...
$$

これは次に見るように対数時間で高速に計算できるので十分間に合います.

$X, Y$が大きいのでオーバーフローには気をつける必要があります.

計算量

$1$から$10^{18}$まで進めるために2倍ずつ進んでいけば距離は1度進むごとに$\frac{1}{2}$になっていきます.
最大で$\log{10^{18}} \approx 60$回進めば答えが出ます.

$$
\log{10^{18}} = 18 \log{10} \approx 18 \cdot 3.32 = 60
$$

解答

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define Int long long
#define MAX_X 1000000000000000000
Int X, Y;

void input() {
  cin >> X >> Y;
}

void solve() {
  int count = 0;
  Int x = X;
  while (x <= Y) {
    count++;
    x *= 2;
  }
  cout << count << endl;
}

int main() {
  input();
  solve();
  return 0;
}