본문 바로가기
Programming/BOJ

#1322 X와 K(Mathematics)

by 작은별하나 2020. 1. 23.
반응형

이번 문제는 Gold IV 난이도 문제이지만, 수학적인 원리를 알고 있으면 아주 쉽게 풀 수 있습니다.

 

주어진 X에 대하여 다음을 만족하는 Y를 구하는데, K번째 Y를 구하는 문제입니다.

\[ X + Y = X | Y \]

여기서 | 연산자는 Bitwise OR 로 비트합을 계산합니다.  비트합은 각 비트끼리 논리합(Logical OR)을 합니다.

이를 만족하는 Y 는 X의 비트 중, 1인 부분은 반드시 0이어야 하고, 0인 부분은 1이든 0이든 상관이 없습니다.

 

만약, X의 비트 중 1인 부분에 같은 위치의 Y의 비트가 1이라고 한다면, 비트합에서는 1이 되지만, 덧셈에서는 0이 됩니다.  어떻게 잘 조합하면 될 것이라고 생각할 수 있지만, 그럴 수 없습니다.  X의 비트와 Y의 비트중 같은 위치에 1이 있다면, 그 중 가장 오른쪽에 비트를 고릅니다.

덧셈에서는 1+1 = 2가 되므로, 실제 비트로는 0이 됩니다.  이것을 1로 바꾸려고 하려면, 자리올림인 캐리(Carry)가 발생해야 하는데, 0+0, 0+1, 1+0 으로는 자리올림이 발생하지 않습니다.  그래서 결국 1로 바꿀 수가 없죠.

 

주어진 X에 대해서 K번째로 작은 수는 K를 1씩 증가하면서 겹치는 비트가 있는지 검사할 수 있습니다.  하지만 이 방법은 X의 비트에 1이 많다고 하면 꽤 많은 반복을 해야 합니다.

 

제가 생각한 방법은 아주 단순합니다.  X의 비트를 나열해놓고, K를 X의 비트중 0인 자리에 맞추어 다시 쓰는 것이죠.

X = 46 이고, K = 13 이라고 한다면, 이를 2진 수로 표현하면 다음과 같습니다.

 

0 0 1 0 1 1 1 0

 

13는 2진수로 \(1101_2\)입니다.  이것을 0이 써진 곳에 맞추어 쓰면,

 

1 1 0 0 0 0 0 1

 

이 됩니다.  그래서 13번째 Y는 \(11000001_2 = 193\)을 얻게 됩니다.

 

이것을 이용하면, 반복해서 맞추어보지 않아도 K번째 수를 알아낼 수 있습니다.

 

제가 작성한 소스입니다.  소스는 참고용으로 봐주세요.

//--------------------------------------------------------------------
//  baekjoon #1322 X and K
//    - by Aubrey Choi
//    - created at 2019-08-17
//--------------------------------------------------------------------
#include <stdio.h>

int main()
{
  long long x, k, s = 0;
  scanf("%lld%lld",&x,&k);
  for(int i=0, j=0; k>>j; i++)
  {
    if((x>>i)&1) continue;
    s |= ((k>>j)&1)<<i;
    j++;
  }
  printf("%lld\n", s);
}
728x90

'Programming > BOJ' 카테고리의 다른 글

#1339 단어 수학(Mathematics)  (0) 2020.01.26
#1325 효율적인 해킹(DFS)  (0) 2020.01.24
#1309 동물원(Dynamic Programming)  (0) 2020.01.19
#1303 전쟁 - 전투 (DFS)  (0) 2020.01.19
#1300 K번째 수 (이분탐색)  (2) 2020.01.16

댓글