PASS486 (중, p. 501)

문제#

image.png


어떻게 풀었나?#

책을 보고 풀진 않았지만, 이 문제를 풀기 전에 책에 나온 에라토스테네스의 체빠른 소인수 분해 에 나온 내용을 읽었어서 난이도 ‘하’ 수준으로 문제를 풀 수 있었다.

어떤 수의 약수의 개수는 소인수 분해 한 결과만 있으면 빠르게 구할 수 있다. 어떤 값이 $x^a \times y^b \times r^c$으로 소인수분해 된다면( $x,y,r$은 소수), 약수의 개수는 $(a+1)(b+1)(c+1)$이 된다.

따라서 에라스토스테네스의 체로 숫자별 최소 소수를 딱 한번 구한 뒤, 빠른 소인수 분해로 약수의 개수를 찾으면 된다.


정답 코드#

#include <bits/stdc++.h>
using namespace std;
#define N 10000000
int mn_prime[N+1];
void Eratosthenes() {
    for(int i=0; i<=N; i++) mn_prime[i] = i;
    int sqrtn = (int)(sqrt(N));
    for(int i=2; i<=sqrtn; i++) {
        if (mn_prime[i] == i) {
            for (int j = i * i; j <= N; j += i) {
                if (mn_prime[j] == j) mn_prime[j] = i;
            }
        }
    }
}
int PrimeFactorCnt(int x) {
    int ans=1, cnt=0;
    int prv_prime = -1;
    while(x>1) {
        if(prv_prime != mn_prime[x]) {
            ans*=(cnt+1);
            cnt=1;
        }
        else cnt++;
        prv_prime = mn_prime[x];
        x/=mn_prime[x];
    }
    if(cnt>0) ans*=(cnt+1);
    return ans;
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int tc; cin >> tc;
    Eratosthenes();
    while(tc--) {
        int n,lo,hi;
        cin >> n >> lo >> hi;
        int ans=0;
        for(int i=lo; i<=hi; i++) {
            if(PrimeFactorCnt(i) == n) ans++;
        }
        printf("%d\n", ans);
        
    }
    return 0;
}

Comment#

빠른 소인수분해 방법이 상당히 인상적이었다.