코딩테스트/백준

[백준][C++]1016번 제곱 ㄴㄴ 수

윤깡패 2023. 7. 2. 18:28

문제

https://www.acmicpc.net/problem/1016

 

1016번: 제곱 ㄴㄴ 수

어떤 정수 X가 1보다 큰 제곱수로 나누어 떨어지지 않을 때, 그 수를 제곱ㄴㄴ수라고 한다. 제곱수는 정수의 제곱이다. min과 max가 주어지면, min보다 크거나 같고, max보다 작거나 같은 제곱ㄴㄴ수

www.acmicpc.net

 

 

풀이

  • 일반적인 반복문으로 구하면 시간 초과가 발생하므로 에라토스테네스의 체 알고리즘 방식을 제곱수 판별 로직에 적용해 문제를 해결한다.
  • min과 max 사이의 수들 안에서 1,000,000의 데이터만 확인한다.

 

에라토스테네스의 체 알고리즘

 

에라토스테네스의 체 알고리즘

에라토스테네스의 체 알고리즘 소수를 구하는 대표적인 판별법 * 소수(Prime Number) : 1과 자기 자신 외에 약수가 존재하지 않는 수 ⇒ 1은 소수가 아니다. 시간 복잡도 : O(Nlog(logN)) + 매우 빠르게 동

soobin0821.tistory.com

 

 

코드

#include <iostream>
#include <vector>
using namespace std;

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  long Min, Max;
  cin >> Min >> Max;

  vector<bool> Check(Max - Min + 1, false);
  for(long i = 2; i * i <= Max; i++)
  {
    long pow = i * i;
    long start_index = Min / pow;
    
    if(Min % pow != 0)
    {
      start_index++;
    }

    for(long j = start_index; j * pow <= Max; j++)
    {
      Check[(int)((j * pow) - Min)] = true;
    }
  }

  int count = 0;
  for(int i = 0; i <= Max - Min; i++)
  {
    if(Check[i] == false)
    {
      count++;
    }
  }

  cout << count;

  return 0;
}

 

 

오답

  • 제곱수 판별 배열을 최댓값과 최솟값의 차이만큼 선언한다.
  • start_index : Min보다 큰 제곱수부터 "제곱수를 true로 변경"하는 반복문이 시작되도록 하는 작업에 사용

 

더보기
#include <iostream>
#include <vector>

using namespace std;

int main() 
{
  ios::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  long Min, Max;
  cin >> Min >> Max;
  // 최댓값과 최솟값의 차이만큼 배열 선언
  vector<bool> Check(Max - Min + 1);

  // 2의 제곱수인 4부터 max보다 작거나 같은 값까지 반복
  for(long i = 2; i * i <= Max; i++)
  {
    long pow = i * i;   // 제곱수
    long start_index = Min / pow;

    // 나머지가 있으면 1을 더해주어야 Min보다 큰 제곱수부터 시작됨
    if(Min % pow != 0)
    {
      start_index++;
    }
    // 제곱수를 true로 변경
    for(long j = start_index; pow * j <= Max; j++)
    {
      Check[(int)((j * pow) - Min)] = true;
    }
  }

  int count = 0;
  // Check 배열에서 제곱이 아닌 수이면 count 증가
  for(int i = 0; i <= Max - Min; i++)
  {
    if(!Check[i])
    {
      count++;
    }
  }

  cout << count << "\n";	// count 출력
  
}

 

[ 정답코드 예시 ]

Min = 10, Max = 15인 경우, "2의 제곱수인 4부터 max보다 작거나 같은 값까지 반복"하는 반복문에서 i = 2일 때

  - pow = i * i = 2 * 2 = 4

  - Min / pow = start_index = 10 / 4 = 2

  - Min % pow = 10 % 4 = 2

 j = start_index++ = (2 + 1)부터 "제곱수를 true로 변경"하는 반복문 시작

  ⇒ Check[(int)((j * pow) - Min)] = Check[(int)((3 * 4) - 10)] = Check[2]

만약 j = (2 + 1)보다 작은 수부터 "제곱수를 true로 변경"하는 반복문 시작할 경우

  ⇒ Check[(int)((j * pow) - Min)] = Check[(int)((2 * 4) - 10)] = Check[-2] ( 오류 )

 

 

 

728x90