알고리즘/algospot

algospot PASS486

꾸준함. 2018. 3. 2. 19:53

문제 링크입니다: https://algospot.com/judge/problem/read/PASS486

완전탐색법과 에라토스테네스의 체, 총 두가지 방법으로 풀어봤습니다.

완전탐색법은 http://jaimemin.tistory.com/440?category=988050와 비슷하게 풀었습니다.

'만취한 상범' 문제에서는 한번 지나갈 때마다 문을 여닫았지만 이 문제에서는 약수의 갯수를 추가했습니다.

에라토스테네스의 체를 이용한 방법은 소인수분해했을 때 약수의 갯수 = Π(i번째 지수+1) 공식을 이용하여 풀었습니다.

예를 들자면 100= 2^2 * 5^2입니다. 따라서 약수의 갯수는 3 * 3 = 9 입니다.

100의 최소 약수인 2를 나누면 50 = 2 * 5^2 이므로 약수의 갯수는 2 * 3 = 6 입니다.

100의 약수의 갯수를 모른다고 가정하고 50의 약수 갯수는 6인걸 알고 있다면 3/2를 곱해 100의 약수의 갯수가 9임을 알 수 있습니다.(2의 지수가 1에서 2로 변했으므로 (2+1)/(1+1))


#include <iostream>

#include <cmath>

#include <cstring> //memset

using namespace std;

 

const int MAX = 10000000; //천만

 

//minFactor[i] -> i의 가장 작은 소인수(i가 소수인 경우 자기 자신)

int minFactor[MAX + 1];

//minFactorPower[i] -> i의 소인수 분해에는 minfactor[i]의 몇 승이 포함되어있는가

int minFactorPower[MAX + 1];

//factors[i] -> i가 가진 약수의 수

int factors[MAX + 1];

 

void erastothenes(void)

{

        //1은 항상 예외 처리

        minFactor[0] = minFactor[1] = -1;

        //모든 숫자를 처음에는 소수로 표시

        for (int i = 2; i <= MAX; i++)

               minFactor[i] = i;

        //에라토스테네스의 체를 수행

        int sqrtN = int(sqrt(MAX)); //루트 N

        for (int i = 2; i <= sqrtN; i++)

               if (minFactor[i] == i)

                       for (int j = i*i; j <= MAX; j += i)

                              //아직 약수를 본적 없는 숫자인 경우 i를 써 둔다

                              if (minFactor[j] == j)

                                      minFactor[j] = i;

}

 

void getFactorsSmart(void)

{

        factors[1] = 1;

        for (int num = 2; num <= MAX; num++)

        {

               //소수인 경우 약수가 두개 뿐

               if (minFactor[num] == num)

               {

                       minFactorPower[num] = 1; //1

                       factors[num] = 2; //약수 두개

               }

               //소수가 아닌 경우, 가장 작은 소인수로 나눈 수의

               //약수의 수를 응용해 num의 약수의 수를 찾는다

               else

               {

                       int prime = minFactor[num];

                       int divisor = num / prime;

                       //divisor prime으로 더이상 나누어지지 않는다면

                       if (prime != minFactor[divisor])

                              minFactorPower[num] = 1;

                       else

                              minFactorPower[num] = minFactorPower[divisor] + 1;

                       int exponent = minFactorPower[num];

                       factors[num] = (factors[divisor] / exponent)*(exponent + 1);

               }

        }

}

 

//완전탐색법

void getFactorsBruteForce(void)

{

        memset(factors, 0, sizeof(factors));

        for (int div = 1; div <= MAX; div++)

               for (int multiple = div; multiple <= MAX; multiple += div)

                       factors[multiple]++;

}

 

int main(void)

{

        int test_case;

        cin >> test_case;

        if (test_case < 1 || test_case>50)

               exit(-1);

 

        erastothenes();

        getFactorsSmart();

        //getFactorsBruteForce();

        for (int i = 0; i < test_case; i++)

        {

               int divisorNum, low, high;

               cin >> divisorNum >> low >> high; //약수 갯수, 범위

               if(divisorNum > 400 || low<1 || low>MAX || high<1 || high>MAX)

                       exit(-1);

 

               int result = 0;

               for (int j = low; j <= high; j++)

                       if (factors[j] == divisorNum)

                              result++;

               cout << result << endl;

        }

        return 0;

}

[에라토스테네스의 체 이용]

[완전탐색법 이용]


개발환경:Visual Studio 2017


지적, 조언, 질문 환영입니다! 댓글 남겨주세요~


[참고] 프로그래밍 대회에서 배우는 알고리즘 문제해결전략

 

반응형

'알고리즘 > algospot' 카테고리의 다른 글

algospot PINBALL  (0) 2018.03.07
algospot POTION  (0) 2018.03.04
c++ 에라토스테네스의 체를 이용한 빠른 소인수 분해  (0) 2018.03.02
algospot FOSSIL  (0) 2018.03.02
UVa Online Judge 10385 - Duathlon  (5) 2018.03.02