관리 메뉴

Mini

[틀림] 백준 1456 거의소수 // 대소비교 최적화방법, 소수판별 본문

Algorithm/수학

[틀림] 백준 1456 거의소수 // 대소비교 최적화방법, 소수판별

Mini_96 2025. 3. 27. 16:31

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

* 풀이1

  • 체 알고리즘 => 소수들 벡터에 저장 ( 루트b까지만 보면됨 )
    • ex) 25까지의 거의소수를구해야함
    • 5까지만 소수를 구하면됨. 구해야됨.
    • 10^14 -> long도 초과, 10^7 -> 1천만 -> ok 
      • 5를넘어가면 (6부터는 6^2 = 36 ...) 거의소수가 될수없음.

  • 1. 소수에대해
  • 2. 소수들을 제곱해가면서 a이상, b이하인지 체크
for(auto i : v) {
   int cnt=0;
   for(ll j=i*i;j<=b;j=j*i) {
      if(j>=a) cnt++;
   }
   ret+=cnt;
}
  • 문제 : j를 계속 곱하기때문에 overflow 발생

 

* 풀이2

  • 이항정리를 이용한 대소비교
  • 이렇게하면 77777^10을 계산해야될것을, 77777^9으로 개선할수있음.

for(auto i : v) {
   int cnt=0;
   ll tmp = i; // 777777(소수)
   while((double)i <= (double)b / (double)tmp) {
      if( (double)i >= (double)a/(double)tmp) {
         cnt++;
      }
      tmp = tmp * i;
   }
   ret+=cnt;
}

 

* 전체코드

#include<bits/stdc++.h>
using namespace std; 

typedef long long ll;

ll a,b,ret;
int sosu[10000000+1];
vector<ll> v;

void make() {
   fill(sosu,sosu+10000000+1,1); //모두 소수라고 가정
   sosu[1]=0;// 1은 소수아님
   for(ll i=2;i*i<=b;++i) {
      if(!sosu[i]) continue;
      for(ll j=2*i;j*j<=b;j+=i) { //소수 i의 배수들은 소수가아님, 시작 : 2*i부터!!
         sosu[j]=0; // 이문제특징 : 소수를 루트b까지만 구하면됨!!!, 다구하면 10^14 -> 터짐
      }
   }

   for(ll i=2;i*i<=b;++i) {
      if(sosu[i]) {
         v.push_back(i);
      }
   }
   
}

int main() {
   ios_base::sync_with_stdio(0);
   cin.tie(0); cout.tie(0);

   cin>>a>>b;
   make();
   for(auto i : v) {
      int cnt=0;
      ll tmp = i; // 777777(소수)
      while((double)i <= (double)b / (double)tmp) {
         if( (double)i >= (double)a/(double)tmp) {
            cnt++;
         }
         tmp = tmp * i;
      }
      ret+=cnt;
   }

   cout<<ret;
   
   return 0;
}