[ 백준 ] 1456 / 거의 소수

金弘均·2021년 9월 15일
0

Baekjoon Online Judge

목록 보기
120/228
post-thumbnail

# Appreciation

/*
 * Problem :: 1456 / 거의 소수
 *
 * Kind :: Math
 *
 * Insight
 * - 10^14 까지의 모든 소수를 구해야 하나 싶었지만,
 *   거의 소수 = 소수^N(>=2) 이므로
 *   10^7 까지의 소수만 구하면 된다
 *
 * - 검사에서 Overflow 가 일어날 수밖에 없네...?
 *   + long 은 8Bytes 로 어림잡아서 9*10^18 까지 나타낼 수 있다
 *     10^6 < P < 10^7 인 소수가 있을 때,
 *     10^24 < P^4 < 10^28 로 거의 소수를 확인하는 도중 범위를 넘어가게 된다
 *     # 주어진 소수 P 가 있을 때,
 *       P^2, P^3, P^4, ... 이렇게 검사하지 말고
 *       P, P^2, P^3, ... 으로 검사하면 Overflow 를 일어나지 않게 할 수 있다
 *     # 이때, A 와 B 도 적당히 처리해 주어야 하는데...
 *       X <= Y 이면, X/Z <= Y/Z
 *       X >= Y 이면, X/Z >= (Y+Z-1)/Z
 *       임을 이용하자!
 *
 * Point
 * - main 함수 안에 (bool)isPrime[10000000+1] 을 선언하니 컴파일이 안된다
 *   하지만 전역변수로 선언하니 컴파일이 된다
 *   # 좀 큰 배열을 선언한다 싶으면 스택을 사용하는 지역배말고
 *     힙을 사용하는 전역배열로 선언하자
 *
 * - 사실 정수에서 Overflow 를 일어나지 않기 위해 이러저러한 처리를 해주었지만,
 *   그냥 long double 을 활용하면 그러한 처리를 하지 않아도 된다
 *   # long double 의 소수점 정밀도가 15자리 이상인데,
 *     10^14 정도의 범위에서 일어나는 정수끼리의 곱셈에서
 *     일의 자리를 바꿀 정도의 오차는 발생하지 않을 것이니까
 */

# Code

//
//  BOJ
//  ver.C++
//
//  Created by GGlifer
//
//  Open Source

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

#define endl '\n'

// Set up : Global Variables
bool isPrime[10000000+1]; /* 이정도 크기면 전역배열로 선언해야만 컴파일이 됨 */

// Set up : Functions Declaration
/* None */


int main()
{
    // Set up : I/O
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    // Process
    memset(isPrime, true, sizeof(isPrime)); /* isPrime 초기화 */
    isPrime[0] = isPrime[1] = false; /* 0과 1은 소수가 아님 */
    vector<long> primes; /* 10^7 이하 소수 저장 */
    /* 에라토스테네스의 체 */
    for (int i=2; i<=10000000; i++) {
        if (isPrime[i]) {
            primes.push_back(i);
            for (int j=i+i; j<=10000000; j+=i) {
                isPrime[j] = false;
            }
        }
    }

    // Set up : Input
    long A, B;
    cin >> A >> B;

    long ans = 0;
    /* 10^7 이하 소수를 크기가 작은 순서대로 하나씩 꺼냄 */
    for (long prime : primes) {
        long val = prime; /* 거의 소수의 현재값 */
        while (val <= B/prime) { /* B 보다 작거나 같고 */
            if (val >= (A+prime-1)/prime) { /* A 보다 크거나 같으면 */
                ans++; /* 카운트해줌 */
            } val *= prime; /* 거의 소수의 값을 갱신 */
        }

        /* 아래 처럼 long double 을 이용해서도 풀 수 있음 */
//      long double val = prime * prime;
//      while (val <= B) {
//          if (val >= A) {
//              ans++;
//          } val *= prime;
//      }
    }

    // Control : Output
    cout << ans << endl;
}

// Helper Functions
/* None */
profile
이런 미친 게임을 봤나! - 옥냥이

0개의 댓글