yutasの競技プログラミング勉強帖

競技プログラミングの問題についての解説記事を主に書いています。

B - CTZ / AtCoder Beginner Contest 336

問題

正の整数  x に対して、  x を2進表記したときに末尾に連続する  0 の個数の最大値を  \mathrm{ctz}(x) と表す。 ただし、  x を2進表記したときに末尾が  1 であれば、  \mathrm{ctz}(x) = 0 である。

正の整数  n が与えられるとき、  \mathrm{ctz}(n) を出力せよ。

入力

最初の1行に、整数  n が与えられる。

条件

  • 実行時間制限: 2s
  • メモリ制限: 1024MB
  •  1 \leq n \leq {10}^{9}

出力

 \mathrm{ctz}(n) を1行で出力すること。

解法

ある整数を2進表記したときに、末尾に  0 k 個並んでいるものとします。 (ただし、末尾から  k + 1 個目の数字は  1 とします。)

このとき、この整数を  x とすると、 \begin{align} x & = \cdots + 1 \cdot {2}^{k} + 0 \cdot {2}^{k - 1} + \cdots + 0 \cdot {2}^{1} + 0 \cdot {2}^{0} \\ & = \cdots + {2}^{k} \end{align} という形になるので、  x {2}^{k} の倍数であり、  {2}^{k + 1} の倍数ではないということが言えます。

従って、与えられた整数  n に対して、割り切れる限り  2 で割ったときの、計算が行えた回数が答えとなります。

 n \leq {10}^{9} であり、この計算は  O(\log n) 程度の計算量で行えるので、これは実行時間制限に間に合います。

ソースコード

main() 関数の中に、答えを出力する部分を直接実装しました。

int main() {
  // 値の入力
  int n;
  cin >> n;

  int ans = 0; // 答えを表す整数 ans

  // n が 2 で割り切れる限り、以下の操作を続ける
  while (n % 2 == 0) {
    ans++; // 答えを1つ増やす
    n /= 2; // n を 2 で割った値にして更新する
  }
  cout << ans << endl; // 答えの出力

  return 0;
}