1. 程式人生 > >#數論# 快速分解質因數的技巧 && 篩法求素數(快速篩)

#數論# 快速分解質因數的技巧 && 篩法求素數(快速篩)

快速分解質因數

在做題時經常遇到要分解質因數,那麼如何快速分解質因數呢?

在用篩法求素數時,我們使用線性篩的方法,並在每次篩的過程中,記錄下每個數的最小質因數。那麼在分解質因數的時候,只需要不斷除以當前數的最小質因數,就可以快速得到分解的質因數了。

給出一個簡單的例子,比如我們要求 50 這個數的質因數:

首先,利用線性篩找到所有的素數,並記錄非素數的最小質因數,然後再將數字 50 除以他的最小質因子(也就是2)得到 25,然後再將數字 25 除以他的最小質因子(也就是5)得到 5,到這為止就做完啦,50 的質因數就是 2 和 5。

篩法求素數

一般的線性篩法

這種方法比較好理解:初始時,假設全部都是素數,當找到一個素數時,顯然這個素數乘上另外一個數之後就一定是合數(注意上面的 i*i , 比 i*2 要快點 ),把這些合數都篩掉,即演算法名字的由來。 但仔細分析能發現,這種方法會造成重複篩除合數,影響效率。比如10,在 i = 2 的時候,k = 2*15 篩了一次;在 i=5,k=5*6 的時候又篩了一次。所以,也就有了快速線性篩法。

void make_prime()
{
    memset(prime, 1, sizeof(prime));
    prime[0] = prime[1] = 0;
    for(int i = 2;  i < n;  i++) {
        if(prime[i]) {
            primes[++cnt] = i;
            for(int j = i * i; j < n; j += i)
                prime[j] = 0;
        }
    }
    return;
}

快速線性篩法

快速線性篩法沒有冗餘,不會重複篩除一個數,所以“幾乎”是線性的,雖然從程式碼上分析,時間複雜度並不是O(n)。

void GetPrime() {
    for(int i = 2; i < n; i++) {
        if(!NotPrime[i]) prime[num_prime++] = i;
        for(int j = 0; j < num_prime && i * prime[j] < n; j++) {
            NotPrime[i*prime[j]] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}