1. 程式人生 > 其它 >質數、質因數個數和約數個數的求解

質數、質因數個數和約數個數的求解

質數的判定

質數也稱素數,是指只能被其自身和1整數的正整數。

那麼如何判斷一個數是否為質數呢?可以用所有小於該數的正整數去試著除該數,若能整數,則不是質數;若這些數都不能整除它,則該數是質數。

要求

給定一個數n,要求判定是否為質數(0,1和負數都不是質數),若是則輸出yes,否則輸出no

程式碼

#include <cstdio>
#include <cmath>
using namespace std;

/*
 * 判斷一個數是否是質數(素數)
 * */
bool Judge(int n){
    if(n<2){	//小於2的數都不是質數
        return false;
    }
    int bound = sqrt(n); // 程式碼優化,只需迴圈到根號n即可
    for (int i = 2; i <= bound; ++i) {
        if (n % i == 0) { 	//如果能被整除則不是質數,返回false
            return false;
        }
    }
    return true;
}
int main(){
    int n;
    while (scanf("%d",&n)!=EOF){
        if(Judge(n)){
            printf("yes\n");
        } else {
            printf("no\n");
        }
    }
    return 0;
}

質數篩法

知道如何判定一個質數後,那麼如何找出0~100000之間的所有質數呢?依次列舉每個數,然後按照上文中的判斷方法確定其是否為質數。這樣做是可行的,但是時間複雜度太高了,這裡有一種更好的方法,那就是質數篩法。

找到一個質數,它的所有倍數均標記為非質數;這樣,當遍歷到一個數時,若它未被任何小於它的數標記為非質數,則確定其為質數

例如:

有這樣20個數(粗體為質數):

  • 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 (初始全部為標記為質數)

  • 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20 (0,1為非質數排除)

  • 0,1,23,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20(2是質數,它的所有倍數均為非質數)

  • 0,1,23,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20(3是質數,它的所有倍數均為非質數)

這樣很快就算出來[0,20]之間的質數了

要求

輸出第k個質數(k<10000),如k=3時,輸出5

程式碼

//
// Created by lxy on 2022/3/15.
//
#include <cstdio>
#include <vector>
using namespace std;

const int MAXN = 1e5 + 10;
vector<int> prime;  //儲存質數
bool isPrime[MAXN]; //用來判斷該數是否為質數

/*
 * 質數篩法
 * */
void Initial(){
    fill(isPrime, isPrime + MAXN, true);// 先假設所有數是質數
    isPrime[0] = false; //  0不是質數
    isPrime[1] = false; //  1不是質數
    for (int i = 2; i < MAXN; ++i) {
        if (!isPrime[i]) { // 不是質數就繼續
            continue;
        }
        prime.push_back(i);//是質數就新增到向量中
        if (i > MAXN / i) { // 等價於i*i>MAXN預防i*i越界int,提前判斷一下
            continue;
        }
        for (int j = i*i; j < MAXN; j+=i) { //質數的倍數肯定是非質數
            isPrime[j] = false;
        }

    }
}
int main(){
    Initial();
    int k;
    while (scanf("%d", &k) != EOF) {
        printf("%d\n", prime[k - 1]);
    }
    return 0;
}

質因子分解

什麼是因子分解呢?

30=2 * 15

​ =5 * 6

​ =2 * 3 * 5 (所有因子都是質數時就稱質因子分解)

通常使用短除法來求質因子:一個數不斷的除以質數,直到等於1為止。例如:

120 / 2 = 60 (從第一個質數開始整除)

60 / 2 = 30

30 / 2 = 15

15 / 3 = 5 (此時2無法整除了,換下一個質數3)

5 / 5 = 1 (此時3也無法整除了,換下一個質數5)

所以\(120=2^3*3*5\)

\(對一個數x分解質因數就是確定質數p_1,p_2,···p_n,使其滿足x=p_1^{e_1}*p_2^{e_2}*···*p_n^{e_n}\)

要求

求正整數N(1<N<10^9)的質因子的個數,相同的質因子需要重複計算。例如120=2 * 2 * 2 * 3 * 5,有5個質因子

程式碼

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

const int MAXN = 4e4;
vector<int> prime;
bool isPrime[MAXN];

/*
 * 質數篩法
 * */
void Initial(){
    fill(isPrime, isPrime + MAXN, true);// 先假設所有數是質數
    isPrime[0] = false;
    isPrime[1] = false;
    for (int i = 2; i < MAXN; ++i) {
        if (!isPrime[i]) { // 不是質數就繼續
            continue;
        }
        prime.push_back(i);//是質數就新增到向量中
        if (i > MAXN / i) { // 預防i*i越界,提前判斷一下
            continue;
        }
        for (int j = i*i; j < MAXN; j+=i) {
            isPrime[j] = false;
        }

    }
}
/*
 * 求質因子個數
 * */
int NumberOfPrimeFactors(int number){
    int answer = 0;
    for (int i = 0; i < prime.size(); ++i) {
        int factor = prime[i];
        if (number < factor) {
            break;
        }
        int exponent = 0;   //記錄被除以的次數,即它的指數
        while (number % factor == 0) { //不停的除以這個質數,直到不能整除為止
            exponent++;
            number /= factor;
        }
        answer += exponent;
    }
    if (number > 1) {// 還有一個大於根號number質因子
        answer++;
    }
    return answer;
}
int main(){
    Initial();
    int number;
    while (scanf("%d", &number) != EOF) {
        printf("%d\n", NumberOfPrimeFactors(number));
    }
    return 0;
}

約數的個數

\[\begin{array}{c} 質因數分解 x=p_1^{e_1}*p_2^{e_2}*···*p_n^{e_n} \\ 數x約數的個數=(e_1+1)*(e_2+1)*···*(e_n+1) \end{array} \]

120=2^3 * 3 * 5

120約數的個數有(3+1) * (1+1)*(1+1)= 16

程式碼


/*
 * 求約數的個數
 * */
#include <cstdio>
#include <vector>
using namespace std;

const int MAXN = 4e4;
vector<int> prime;
bool isPrime[MAXN];

/*
 * 質數篩法
 * */
void Initial(){
    fill(isPrime, isPrime + MAXN, true);// 先假設所有數是質數
    isPrime[0] = false;
    isPrime[1] = false;
    for (int i = 2; i < MAXN; ++i) {
        if (!isPrime[i]) { // 不是質數就繼續
            continue;
        }
        prime.push_back(i);//是質數就新增到向量中
        if (i > MAXN / i) { // 預防i*i越界,提前判斷一下
            continue;
        }
        for (int j = i*i; j < MAXN; j+=i) {
            isPrime[j] = false;
        }

    }
}
/*
 * 求約數個數
 * */
int NumberOfFactors(int number){
    int answer = 1;
    for (int i = 0; i < prime.size(); ++i) {
        int factor = prime[i];
        if (number < factor) {
            break;
        }
        int exponent = 0;   //記錄被除以的次數,即它的指數
        while (number % factor == 0) { //不停的除以這個質數,知道除不動
            exponent++;
            number /= factor;
        }
        answer *= exponent + 1;
    }
    if (number > 1) {
        answer *= 2;
    }
    return answer;
}
int main(){
    Initial(); 
    int n;
    scanf("%d",&n);
    printf("%d\n", NumberOfFactors(n));
    return 0;
}