ABC083 C - Multiple Gift

Calendar Clock iconCalendar Clock icon

atcoder

目次

# 問題

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

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

  • XAiYX \leq A_i \leq Y - ①
  • Ai+1=kAiA_{i+1} = k A_i - ②
  • Ai<Ai+1A_i < A_{i+1} - ③

# 入力

X Y

# 出力

N

# 入出力例

3 20
3

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

# 解説

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

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

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

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

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

# 計算量

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

log1018=18log10183.32=60\log{10^{18}} = 18 \log{10} \approx 18 \cdot 3.32 = 60

# 解答

// C++ 14
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <unordered_map>
#include <math.h>

#define ll long long
#define Int int
#define loop(x, start, end) for(Int x = start; x < end; x++)
#define loopdown(x, start, end) for(int x = start; x > end; x--)
#define rep(n) for(int x = 0; x < n; x++)
#define span(a,x,y) a.begin()+x,a.begin()+y
#define span_all(a) a.begin(),a.end()
#define len(x) (x.size())
#define last(x) (*(x.end()-1))

using namespace std;
#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;
}

リモートフリーランス。ウェブサービス、スマホアプリエンジニア。
東アジアを拠点に世界を移動しながら活動してます!

お仕事のご依頼・お問い合わせはこちら

コメント