문제 : https://www.acmicpc.net/problem/1456
[알고리즘풀이]
A ~ B 범위에 있는 P^k 꼴의 수를 모두 Count 해주는 문제입니다.
-1) 소수 찾기.
B의 최대 범위는 10^14 이고 , P^k( k ≥ 2 )꼴의 수는 k가 2보다 크거나 같고 10^14보다는 작거나 같으므로,
10^7 이하의 소수만 먼저 찾으면 된다. (10^7 이상의 소수는 제곱했을 때, 입력 범위를 벗어나므로 )
10^7은 배열로 선언이 가능하므로, 에라토스테네스 체를 이용해서 모든 소수를 먼저 구해야 한다.
#define size 10000001
bool p[size];
long long i, j;
for (i = 2; i < size; i++) {
if (p[i] == false) {
for (j = (i * i); j < size; j += i)
p[j] = true;
}
}
bool 배열인 p 배열에는 소수면 false, 소수가 아닌 합성수면 true가 저장됩니다.
-2) A ~ B 까지 P^k 꼴의 수를 찾기.
bool 배열인 p를 순회하며 소수를 발견하면 p * p 가 B보다 작거나 같다면, p 를 계속 곱해가며, A랑 B사이에 있는 P^k 꼴을 찾아줄 수 있다.
이때, p 를 계속 곱해나가다 p^k 꼴이 long long 범위를 벗어나는 경우가 생기므로 if 문을 통해 잡아줘야 된다.
( p 가 10^7보다는 작거나 같지만 10^7에 근접한 소수이고, B가 10^14라면 p * p 는 B보다 작거나 같으므로 while문이 실행된다. 하지만, p * p * p 인 p^3은 10^21에 근접하므로 long long 범위를 벗어나고, 오류가 발생한다.
이 문제가 정답 비율이 낮은 이유는 long long 범위를 벗어나는 경우를 못 잡아줘서 인 것 같다. )
for (i = 2; i < size; i++) {
if (i * i > B)
break;
if (p[i] == false) { // 소수를 찾았으면 소수의 k제곱꼴이 A, B사이에 몇개있는지 찾자.
long long temp = i * i;
while (temp <= B) {
if (A <= temp) {
ans++;
}
temp *= i; // temp = p^k 꼴
if (temp % i != 0) // long long 범위를 벗어나는 경우.
break;
}
}
}
-3) 최종 코드
#include<iostream>
using namespace std;
#define size 10000001
int p[size];
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
long long i, j;
for (i = 2; i < size; i++) {
if (p[i] == false) {
for (j = (i * i); j < size; j += i)
p[j] = true;
}
}
long long A, B, ans = 0;
cin >> A >> B;
for (i = 2; i < size; i++) {
if (i * i > B)
break;
if (p[i] == false) { // 소수를 찾았으면 소수의 k제곱꼴이 A, B사이에 몇개있는지 찾자.
long long temp = i * i;
while (temp <= B) {
if (A <= temp) {
ans++;
}
temp *= i;
if (temp % i != 0)
break;
}
}
}
cout << ans;
}
'Problem Solving > BOJ' 카테고리의 다른 글
[BOJ] 2161 - 카드1 (0) | 2019.10.04 |
---|---|
[BOJ] 9421 - Happy Prime Number (0) | 2019.10.03 |
[BOJ] 1715 - 카드 정렬하기 (0) | 2019.10.02 |
[BOJ] 2225 - 합분해 (0) | 2019.10.01 |
[BOJ] 1914 - 하노이 탑 (0) | 2019.10.01 |