이 튜토리얼에서는 이진 배열의 접두사 중 주어진 값 x로 나누어 떨어지는 것의 개수를 구하는 프로그램을 살펴보겠습니다.
문제에서는 0과 1로만 구성된 이진 배열과 정수 값 x가 주어집니다. 우리의 목표는 배열의 각 위치까지의 접두사(앞부분)를 하나의 이진수로 해석했을 때, 그 값이 x로 나누어 떨어지는 경우의 수를 세는 것입니다.
문제 이해하기
예를 들어, 배열 {1, 0, 1, 0, 1, 1, 0}과 x = 2가 주어졌다고 가정해 보겠습니다. 각 인덱스까지의 접두사를 이진수로 변환하면 다음과 같습니다.
- 1 → 1 (나누어 떨어지지 않음)
- 10 → 2 (✓ 나누어 떨어짐)
- 101 → 5 (나누어 떨어지지 않음)
- 1010 → 10 (✓ 나누어 떨어짐)
- 10101 → 21 (나누어 떨어지지 않음)
- 101011 → 43 (나누어 떨어지지 않음)
- 1010110 → 86 (✓ 나누어 떨어짐)
조건을 만족하는 접두사는 총 3개이므로 결과값은 3이 됩니다.
접근 방법
핵심 아이디어는 간단합니다. 기존 접두사 값에 새 비트를 추가할 때는 number * 2 + arr[i] 공식으로 값을 갱신할 수 있습니다. 이렇게 하면 매번 처음부터 이진수를 다시 계산하지 않고도 현재 접두사의 십진수 값을 O(1)에 효율적으로 유지할 수 있습니다.
예제 코드
#include <bits/stdc++.h>
using namespace std;
// x로 나누어 떨어지는 접두사를 가진
// 원소의 개수를 세는 함수
int count_divx(int arr[], int n, int x){
int number = 0;
int count = 0;
for (int i = 0; i < n; i++) {
// 현재 접두사의 십진수 값 갱신
number = number * 2 + arr[i];
// 조건을 만족하면 카운트 증가
if ((number % x == 0))
count += 1;
}
return count;
}
int main(){
int arr[] = { 1, 0, 1, 0, 1, 1, 0 };
int n = sizeof(arr) / sizeof(arr[0]);
int x = 2;
cout << count_divx(arr, n, x);
return 0;
}
출력 결과
3
코드 설명
count_divx()함수는 배열, 배열의 크기 n, 나눌 값 x를 매개변수로 받습니다.- 반복문을 돌며
number = number * 2 + arr[i]를 통해 현재 위치까지의 접두사를 십진수로 변환합니다. number % x == 0조건을 만족하면 카운트를 1 증가시킵니다.- 모든 원소를 확인한 후 최종 카운트를 반환합니다.
시간 복잡도
배열을 한 번만 순회하면 되므로 시간 복잡도는 O(n)이며, 추가 공간은 상수 수준인 O(1)입니다. 다만 배열의 길이가 매우 길면 접두사 값이 자료형 범위를 초과할 수 있으므로, 실제 환경에서는 long long을 사용하거나 모듈러 연산을 활용하는 것이 안전합니다.