高速な素因数分解

解説

まず、ある数字Nが持つ最小の素因数pを持つ配列sieveを作成します。
つまり、sieve(N) = pとなっています。
このような配列は、最初に昇順に数字を入れておいた配列sieveに対して、インデックスNと、その要素pが等しいところからエラトステネスの篩の要領でループを回すことで作成できます。

次に、上で作成した配列sieveを用いて、ある数字M素因数分解することを考えます。
これは、今現在の値のもつ最小の素因数で割り続けることで実現できます。
この方法だと高々logオーダーで計算することが出来ます。

計算量は、最大の数をNとすると篩を準備するフェーズでO(NloglogN)となります。
また、素因数分解する数をMとすると、O(logM)素因数分解出来ます。

コード

ABC177Eでverifyしました。
この問題では、k個の数を素因数分解しているので最大の計算量は、 O(NloglogN + klogM)となります。
Submission #18055027 - AtCoder Beginner Contest 177

struct SmartPrimeFactorize {
    vector<int> sieve;

    SmartPrimeFactorize(int Max_N) : sieve(Max_N + 1, 0) {
        //コンストラクタ中で篩を構築
        for (int i = 0; i <= Max_N; i++) sieve[i] = i;

        for (int i = 2; i * i <= Max_N; i++) {
            if (sieve[i] == i) {
                for (int j = i + i; j <= Max_N; j += i) {
                    sieve[j] = i;
                }
            }
        }
    }

    
    vector<int> prime_factorize(int n) {
        vector<int> fact;
        while (n != 1) {
            fact.push_back(sieve[n]);
            n /= sieve[n];
        }
        return fact; //素因数を列挙した配列を返す
    }
};