Stunning Garbanzo
open main menu
Part of series: PS

9527 BOJ

/ 3 min read

문제

접근

이분 탐색과 비트마스킹을 이용해 해결하였다.

각 자리별로, 해당 자리가 1인 수의 개수를 세어 전부 더하는 방식으로 해결하였다. 0번째 자리의 경우 0001, 0011, 0101 등 0번째 자리의 비트가 1인 수의 개수를 센다. 이를 위해서 n번째 자리가 1인 최댓값과 최솟값을 구하고, 해당 값들에서 n번째 자리를 배제한 후 서로 빼는 식으로 개수를 센다.

대부분의 사람들은 최댓값과 최솟값을 따로 구하지 않고, 누적합을 이용해서 해결하는 것 같다. 누적합을 이용하는 방식이 더 깔끔하게 나오긴 한다.

코드

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef const ll cll;

cll NBIT = 55, DV = 1e16, ONE = 1;
ll a, b;

ll find(ll bit) {
  ll ground = (ONE << bit);
  if (ground > b) {
    return 0;
  }

  ll st = 0, en = DV, minV, maxV;
  while (st <= en) {
    ll mid = (st + en) / 2;
    if ((ground | mid) >= a) {
      minV = ground | mid, en = mid - 1;
    } else {
      st = mid + 1;
    }
  }

  st = 0, en = DV;
  while (st <= en) {
    ll mid = (st + en) / 2;
    if ((ground | mid) <= b) {
      maxV = ground | mid, st = mid + 1;
    } else {
      en = mid - 1;
    }
  }

  ll lwMsk = (ONE << (bit + 1)) - 1, upMsk = ~lwMsk, result = 1;

  result += (lwMsk & maxV) - (lwMsk & minV);
  result += ((upMsk & maxV) >> 1) - ((upMsk & minV) >> 1);

  return result;
}

int main(void) {
  ios::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  cin >> a >> b;

  ll result = 0;
  for (ll bit = 0; bit < NBIT; ++bit) {
    result += find(bit);
  }

  cout << result << "\n";

  return 0;
}