백준/골드
[백준 1052번] 물병 (C++)
게임개발기원
2025. 4. 12. 19:48
문제링크 : https://www.acmicpc.net/problem/1052
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int N, K;
int main() {
int N, K;
cin >> N >> K;
int add = 0;
while (__builtin_popcount(N) > K) {
N++;
add++;
}
cout << add;
return 0;
}
먼저 1~10까지 직접 그려보며 규칙을 찾아보았다.
2
1 1 -> 2 (10)
3
1 1 1 -> 2, 1 (11)
4
1 1 1 1 -> 2, 2 -> 4 (100)
5
1 1 1 1 1 -> 2, 2, 1 -> 4, 1 (101)
6
1 1 1 1 1 1 -> 2, 2, 2 -> 4, 2 (110)
7
1 1 1 1 1 1 1 -> 2, 2, 2, 1 -> 4, 2, 1 (111)
8
1 1 1 1 1 1 1 1 -> 2, 2, 2, 2 -> 4, 4 -> 8 (1000)
9
1 1 1 1 1 1 1 1 1 -> 2, 2, 2, 2, 1 -> 4, 4, 1 -> 8, 1 (1001)
10
1 1 1 1 1 1 1 1 1 1 -> 2, 2, 2, 2, 2 -> 4, 4, 2 -> 8, 2 (1010)
이를 보면 2의 제곱 수에 대해서는 1개의 병만 있으면 되며, 나머지 병의 개수를 보면 2의 제곱으로 이루어진 것을 볼 수 있다.
따라서 이를 2진법으로 표현이 가능하며, 마지막 병의 개수가 2진법에서 1의 개수인 것을 알 수 있다.
따라서 1차적으로 입력받은 N에 대해 2진법으로 바꾸고 1의 개수를 체크하여 K보다 작거나 같다면 정답이다.
이제 K보다 큰 경우이다.
K보다 크면 이제 이진법에 1을 더해주며 물병의 개수를 추가해준다.
이진법에서 1을 계속 더해주면 결국 1이 사라지고 0으로 바뀌므로, K값 보다 작은 물병의 개수를 알 수 있다.
위 과정을 반복하며 더해준 총 물병의 개수가 우리가 찾는 정답이 된다.
검색을 통해 간단한 함수를 알게 되었는데, gcc 의 내장 함수인 __builtin_popcount(N) 함수를 통해 간단하게 입력받은 N에 대한 이진법 1의 개수를 찾는 것이 가능하다.
또한 C++20의 경우 popcount(N) 표준 함수를 통해 구할 수 있다는 것 또한 알았다.
이를 다르게 표현하면, 직접 & 연산을 통해 1을 체크하고, 자릿수를 밀면서 1의 개수를 모두 체크해주면 된다.
int add = 0; //더해지는 수 (추가 물병 수)
while(1)
{
int cnt = 0; //1의 개수 카운팅
int tmp = N;
while(tmp)
{
cnt += tmp&1; //현재 1 체크
tmp >>= 1; //밀면서 전부 체크
}
if(cnt <= K) break; //조건 체크
N++; //1 더해주기 (물병 추가)
add++;
}