Round 3 250 - SieveOfEratosthenes
問題
wikipedia:エラトステネスの篩を行うときに,最後に省かれる合成数は何?
考え方
合成数 n は n=pq (p<q) と書ける.篩の過程では p(が素数として)での篩の時に消えるので,考えるべきは最小素因数.また,最小素因数 p が同じになる n=pq と m=pr (q<r) については m の方が後に省かれる.
なので求めるべきは最小素因数が最大になる数で,そのなかでも最大の数.実質的に n=pq のとき q も素数であればいい…と言いたいが,例外がある.
2 素数 p<q のもとで pq<p3≦n<q2となる場合には p3 を出力する必要がある.で,その条件を満たすのは n=8 の場合だけなので例外処理でも書けばOK.
コード
とりあえず偶数処理だけ別にして(しなくても間に合うっぽいけど)高速にしたコード.
#include <vector> #include <cmath> using namespace std; class SieveOfEratosthenes { vector<bool> prime; void init(int maxNum) { int sq = (int)sqrt((double)maxNum); int ssq = (int)sqrt((double)sq); prime.resize(sq/2+10, true); prime[0] = false; // == 1 for( int i = 1 ; i <= ssq ; ++i ) { int p = 2 * i + 1; for( int j = p * p / 2 ; j < prime.size() ; j += p ) prime[j] = false; } } bool isPrime(int n) { int sq = (int)sqrt((double)n) / 2; for( int i = 1 ; i <= sq ; ++i ) if( prime[i] && n % (2 * i + 1) == 0 ) return false; return true; } public: int lastScratch(int maxNum) { init(maxNum); switch(maxNum) { case 4: case 5: return 4; case 6: case 7: return 6; case 8: return 8; default: int p = (int)sqrt((double)maxNum), q; if( p % 2 == 0 ) --p; for( p /= 2 ; p > 0 ; --p ) if( prime[p] ) break; p = 2 * p + 1; q = maxNum / p; if( q % 2 == 0 ) --q; for( ; q > p ; q -= 2 ) if( isPrime(q) ) break; return (p * q); } } };