일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
Tags
- 백준 9527번
- ccw 알고리즘
- MongoDB
- Prisma
- Keys
- 그리디
- Github
- 게임 서버 아키텍처
- map
- string
- 이분 탐색
- 자바스크립트
- trie
- DP
- MySQL
- Next
- 그래프 탐색
- Express.js
- PROJECT
- vector insert
- branch
- router
- 트라이
- localstorage
- pm2
- ERD
- HTTP
- html5
- JavaScript
- insomnia
Archives
- Today
- Total
dh_0e
[PS] 1의 개수 세기 / C++ (백준 9527번) 본문
A, B가 $10^{16}$까지 이므로 $O(logn)$에 해결해야 한다.
$O(n)$은 무조건 시간초과.
풀이 과정
2진수에 나타나는 1의 개수를 구해보면 패턴을 찾을 수 있다.
1{1}, 2~3{1, 2}, 4~7{1, 2, 2, 3}, 8~15{1, 2, 2, 3, 2, 3, 3, 4} 까지만 봐도 패턴이 보인다.
d[i] = $2^i$ ~ $2^{i+1}-1$에서 1의 개수라고 했을 때 점화식은 $d[i]=d[i-1]*2+2^{i-1}$로 구할 수 있으며 이를 각 구역으로 봤을 때, 각 구역별로 절반씩 나눠보면 똑같은 패턴인 것이 확인된다.
8~15{1, 2, 2, 3, 2, 3, 3, 4}를 반으로 나누면 8~11{1, 2, 2, 3}, 12~15{2, 3, 3, 4}로 나눠지고 반으로 나눈 right 집합은 left+1임을 알 수 있다. 이를 또 쪼개봐도 8~9{1, 2}, 10~11{2, 3}으로 패턴은 성립한다.
이 패턴을 이용하여 재귀식을 짜주면 된다.
18~30을 재귀로 돌린다 가정했을 때 다음과 같이 범위가 맞을 때까지 반으로 나누고, 최종적으로 값을 다 더하면 범위 내의 1의 개수를 구할 수 있다.
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll d[101];
ll f(ll st, ll en, ll cmp, ll tar_front, ll tar_back) {
if (st == tar_front && en == tar_back)return cmp;
ll mid = (st + en) / 2, cmp_left = (cmp - (en - st + 1) / 2) / 2, cmp_ret = 0;
if(st<=tar_front&&tar_front<=mid)
cmp_ret += f(st, mid, cmp_left, tar_front, tar_back < mid ? tar_back : mid);
if (en >= tar_back && tar_back >= mid + 1)
cmp_ret += f(mid + 1, en, cmp - cmp_left, tar_front > (mid + 1) ? tar_front : (mid + 1), tar_back);
return cmp_ret;
}
int main()
{
ll A, B, dap = 0;
scanf("%lld %lld", &A, &B);
d[0] = 1;
if (A == 1) {
A = 2;
dap = 1;
}
for (int i = 1; ; i++) {
ll i_pow = pow(2, i);
if (B < i_pow)break;
d[i] = d[i - 1] * 2 + i_pow / 2;
ll st = i_pow, en = i_pow * 2 - 1;
if (st <= A && A <= en) {
if (B < en)
dap += f(st, en, d[i], A, B);
else {
dap += f(st, en, d[i], A, en);
A = en + 1;
}
}
}
printf("%lld\n", dap);
return 0;
}
'알고리즘 > Baekjoon' 카테고리의 다른 글
[PS] 후위 표기식 / C++ (백준 1918번) (0) | 2025.04.20 |
---|---|
[PS] 공항 / C++ (백준 10775번) (0) | 2025.04.11 |
[PS] 뱀과 사다리 게임 / C++ (백준 16928번) (0) | 2025.04.09 |
[PS] 너 봄에는 캡사이신이 맛있단다 / C++ (백준 15824번) (0) | 2025.04.02 |
[PS] 박성원 / C++ (백준 1086번) (0) | 2025.03.25 |