mojo's Blog

[백준 9527] 1의 개수 세기 본문

백준/etc

[백준 9527] 1의 개수 세기

_mojo_ 2021. 11. 7. 20:52

문제 링크 => 9527번: 1의 개수 세기 (acmicpc.net)

 

9527번: 1의 개수 세기

두 자연수 A, B가 주어졌을 때, A ≤ x ≤ B를 만족하는 모든 x에 대해 x를 이진수로 표현했을 때 1의 개수의 합을 구하는 프로그램을 작성하시오. 즉, f(x) = x를 이진수로 표현 했을 때 1의 개수라

www.acmicpc.net

 

수학을 이용한 문제이다.

 

먼저 규칙성을 발견하면 다음과 같다.

 

(1) 2^0 ~ 2^1 - 1 일 때 1의 개수의 합 : 1 = 1 + 0

 

(2) 2^1 ~ 2^2 - 1 일 때 1의 개수의 합 : 3 = 2 + 1

 

(3) 2^2 ~ 2^3 - 1 일 때 1의 개수의 합 : 8 = 4 + 4

 

(4) 2^3 ~ 2^4 - 1 일 때 1의 개수의 합 : 20 = 8 + 12  (아래 table을 보자)

 

8 1 0 0 0
9 1 0 0 1
10 1 0 1 0
11 1 0 1 1
12 1 1 0 0
13 1 1 0 1
14 1 1 1 0
15 1 1 1 1

 

위와 같이 8 + 12 = 2^3 + 3 * 2^(3 - 1) 으로 20을 유도할 수 있다.

 

즉, 이걸 일반화 한다면 다음과 같다.

 

2^n ~ 2^(n + 1) - 1 일 때 1의 개수의 합 : 2^n + n * 2^(n - 1)

 

 

 

그러나 문제점이 있다.

 

 

1 ~ 13 을 더할 때 1의 개수의 합을 구할 때 위에서 발견한 방법을 이용한다면... (result = 0)

 

먼저 1 ~ x 에 대한 1의 총 합을 구하는 함수 Solution(x) 라고 정의하자.

(Solution(x) => 1 에서 x 까지의 1에 대한 총 합을 반환하는 함수)

 

(0) main 에서 Solution(13) 을 호출 (result = Solution(13))

     그리고 Solution 함수에 대한 처리가 진행된다.

 

(1) 2^0 ~ 2^1 - 1 에 전부 속하므로 result += 1

 

(2) 2^1 ~ 2^2 - 1 에 전부 속하므로 result += 3

 

(3) 2^2 ~ 2^3 - 1 에 전부 속하므로 result += 8

 

(4) 2^3 ~ 2^4 - 1 에 부분적으로 속하므로 result += ??? (위 방법만으로는 알 수 없음)   

 

부분적으로 속하는 경우에 대한 처리가 필요하다.

 

8 1 0 0 0
9 1 0 0 1
10 1 0 1 0
11 1 0 1 1
12 1 1 0 0

 

여기서 알 수 있는 점은 다음과 같다.

 

(1) 8, 9, 10, 11, 12 에 대한 MSB는 항상 1이라는 점이다.

     즉, result += (12 - 8 + 1) 에 대한 처리를 할 수 있다.

 

(2) MSB 를 제외한 나머지 bit들을 살펴보자.

     나머지 bit들에 대한 1의 개수들의 합은 1 ~ 4 에 대한 1의 개수들의 총 합이 되어버린다.

 

즉, recursion 문제이므로 나머지 bit들에 대한 1의 개수들의 합은 다음과 같이 재귀적으로 구할 수 있다.

 

result += solution(12 - 8)   <= 즉, 1 ~ 4 에 대한 1의 총 합을 재귀적으로 더해줘야 한다.

 

 

Solution Code 

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

long long power[100];

long long solution(long long N) 
{
	if (N == 0)
		return 0;
	if (N == 1)
		return 1;

	long long x, ret, tmp;

	x = 1, ret = 1;
	tmp = N / 2;
	while (tmp != 1) {
		ret += power[x] + x * power[x - 1];
		tmp /= 2;
		x++;
	}

	return ret = ret + N - power[x] + 1 + solution(N - power[x]);
}

int main(void) 
{
	int i;
	long long A, B;
	scanf("%lld %lld", &A, &B);

	power[0] = 1;
	for (i = 1; i < 100; i++)
		power[i] = power[i - 1] * 2;

	printf("%lld", solution(B) - solution(A - 1));

	return 0;
}

 

 

'백준 > etc' 카테고리의 다른 글

[백준 2211] 네트워크 복구  (0) 2021.12.30
[백준 5052] 전화번호 목록  (0) 2021.11.08
[백준 10986] 나머지 합  (0) 2021.10.29
[백준 2829] 아름다운 행렬  (0) 2021.10.05
[백준 5904] Moo 게임  (0) 2021.09.16
Comments