1016번: 제곱 ㄴㄴ 수
문제
https://www.acmicpc.net/problem/1016
1016번: 제곱 ㄴㄴ 수
어떤 정수 X가 1보다 큰 제곱수로 나누어 떨어지지 않을 때, 그 수를 제곱ㄴㄴ수라고 한다. 제곱수는 정수의 제곱이다. min과 max가 주어지면, min보다 크거나 같고, max보다 작거나 같은 제곱ㄴㄴ수
www.acmicpc.net
풀이
min 이상 max 이하의 제곱 ㄴㄴ 수의 개수를 구하는 문제다. 제곱 ㄴㄴ 수란 어느 제곱수로 나누어 떨어지지 않는 수를 말한다.
이 문제의 핵심은 에라토스테네스의 체의 변형이다.
- 1 ≤ min ≤ 1,000,000,000,000
- min ≤ max ≤ min + 1,000,000
위와 같은 범위 때문에 애를 먹었다. 아래 범위 조건 때문에 0 ≤ max - min ≤ 1,000,000 이므로 배열의 크기는 1,000,000 + 1의 크기로 충분함을 알 수 있다. (런타임 에러를 10번 내고서야 이걸 한참 뒤에 깨닫고 겨우 풀었다.)
그리고 2의 제곱부터 4, 8, 12,... 하나하나 없애는 건 10e12라는 범위를 절대 커버할 수 없음이 명백해 보였다. 그래서 최소한의 경우, 필요한 경우만 순회하자 했다.
n * i * i 가 max 이하인 동안 n을 제거해주면 된다. 이 n은 min을 i * i 로 나눈 몫부터 차례대로 순회하면 최소한으로 확인할 수 있다.
(min을 i*i로 나누어 떨어지지 않으면 n에 1을 더해준다. - 범위가 벗어나기 때문)
따라서 n * i * i 가 min 이상 max 이하일 때, sieve[n * i * i - min] 값을 0으로 바꾸었다.
그리고 sieve 배열에서 값이 1인 개수를 세주었다. (sieve 배열의 0~max-min index의 모든 원소의 합)
코드
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL);
long long min, max;
cin >> min >> max;
vector<long long> sieve(1000001, 1);
for (long long i = 2; i * i <= max; i++) {
long long n = min / (i * i);
if (min % (i * i))
n++;
while (n * i * i <= max) {
sieve[n * i * i - min] = 0;
n++;
}
}
cout << accumulate(sieve.begin(), sieve.begin() + max - min + 1, 0) << '\n';
return 0;
}
'Problem Solving > BOJ' 카테고리의 다른 글
[백준 / BOJ] C++ 1865 웜홀 (0) | 2023.02.22 |
---|---|
[백준 / BOJ] C++ 11657 타임머신 (0) | 2023.02.22 |
[백준 / BOJ] C++ 9694 무엇을 아느냐가 아니라 누구를 아느냐가 문제다 (1) | 2023.02.21 |
[백준 / BOJ] C++ 2307 도로검문 (0) | 2023.02.21 |
[백준 / BOJ] C++ 1545 안티 팰린드롬 (0) | 2023.02.21 |