日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法刷题-数论-质数的判定、分解质因数、筛质数

發布時間:2025/4/5 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法刷题-数论-质数的判定、分解质因数、筛质数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 數論
      • 1. 質數
        • 質數的判定---試除法
        • 分解質因數---試除法
        • 篩質數
          • 樸素篩法
          • 埃氏篩法
          • 線性篩法

數論

1. 質數

質數:在大于1的整數中,如果只包含1和它本身這兩個約數,那么這個數就稱為質數。

判斷質數最暴力的寫法,按照質數的定義:看是否有其他的因子。

最樸素的暴力的時間復雜度O(n)

//時間復雜度O(n) bool isPrime(int n){if(n<2) return false;for(int i=2;i<n;i++)if(n%i==0) return false;return true;}

質數的判定—試除法

題目鏈接:Acwing866. 試除法判定質數

優化:枚舉到n\sqrt{n}n?,因為因數都是成對出現的,
如果d是n的因子,那么n/d也是n的因子,所以只需要枚舉一部分就行,枚舉哪一部分呢?就是d≤n/d 推出,d≤nd≤\sqrt{n}dn?

這里n\sqrt{n}n?的寫法需要注意,這種調用數學函數n\sqrt{n}n?的寫法不好,太慢;另外寫成i?i≤ni*i≤ni?in存在溢出風險,最好的寫法是i≤n/ii≤n/iin/i

試除法求質數的時間復雜度O(n\sqrt{n}n?)

//優化成O(根號n) bool isPrime(int n){if(n<2) return false;for(int i=2;i<=n/i;i++)if(n%i==0) return false;return true;}

分解質因數—試除法

題目鏈接:Acwing867. 分解質因數

暴力求質因數

下面i就是質因子,s是質因子i的階數。

暴力的時間復雜度O(n)

void divide(int n){for(int i=2;i<=n;i++){if(n%i==0){ //i一定是質數,因為下面n/=i,n一直在更新,如果是合數的話,已經被2除干凈了int s=0;//統計質因子的階數while(n%i==0){s++;n/=i;}cout<<i<<" "<<s<<endl;}} }

優化

給出一個重要性質:正整數n的因子中,最多包含1個大于n\sqrt{n}n?的質因子。(可以用反證法來證明)

這里試除法的優化就是枚舉到n\sqrt{n}n?,然后剩下的1個大于n\sqrt{n}n?的質因子單獨處理,這樣試除法分解質因數的時間復雜度O(n\sqrt{n}n?)

ac代碼

#include<bits/stdc++.h> using namespace std;//試除法分解質因數 void divide(int n){//處理≤sqrt(n)的質因子for(int i=2;i<=n/i;i++){if(n%i==0){int s=0;while(n%i==0){s++;n/=i;}cout<<i<<" "<<s<<endl;}}//單獨處理大于sqrt(n)的質因子if(n>1) cout<<n<<" "<<1<<endl;}int main(){int n;cin>>n;int tmp;for(int i=0;i<n;i++){cin>>tmp;divide(tmp);cout<<endl;}}

篩質數

題目鏈接acwing868. 篩質數

樸素篩法

樸素篩法的思想:從小到大枚舉所有數,每次刪掉該數的所有倍數,比如枚舉到2,就刪掉所有2的倍數。枚舉到3,就刪掉所有3的倍數。

需要用到prime數組,用來存放所有的質數;st數組,用來記錄是否是某個數的倍數,即判斷哪些是質數。需要count1變量,來存儲質數的個數。

遍歷的時候,需要考慮等號取不取。

樸素篩法的時間復雜度O(n×logn)O(n\times logn)O(n×logn)

#include<bits/stdc++.h> using namespace std;const int maxn=1000010;int prime[maxn];//prime數組存的是從小到大的質數 int count1=0; //質數的個數 bool st[maxn]; //判斷是否是質數//樸素的篩法 void primeNumber(int n){for(int i=2;i<=n;i++){if(!st[i]){ //i不是別人的倍數,那么就是質數prime[count1++]=i;}for(int j=i+i;j<=n;j+=i) st[j]=true;//倍數篩掉}cout<<count1<<endl;}int main(){int n;cin>>n;primeNumber(n);return 0;}
埃氏篩法

優化:不需要篩掉所有數的倍數(合數的倍數一定不是質數,不用管),只需要篩掉質數的倍數,(因為質數的倍數是合數)。

//優化的篩法 void primeNumber1(int n){for(int i=2;i<=n;i++){if(!st[i]){ //i不是別人的倍數,那么就是質數prime[count1++]=i;for(int j=i+i;j<=n;j+=i) st[j]=true;//質數的倍數篩掉} }cout<<count1<<endl;}

有質數定理:當n很大時,1~n中有nlnn\frac{n}{lnn}lnnn?個質數。

優化的篩法(埃氏篩法)時間復雜度O(n×loglogn)O(n\times loglogn)O(n×loglogn),可以粗略地看成是O(n)。

兩次提交結果

線性篩法

先說效率,數量級在10^7時候,線性篩法比埃氏篩法快一倍大概。
線性篩法時間復雜度O(n)

線性篩法的核心:一個數k只會被k的最小質因子篩掉。

//線性篩法void primeNumber2(int n){for(int i=2;i<=n;i++){if(!st[i]) prime[count1++]=i;for(int j=0;prime[j]<=n/i;j++){st[prime[j]*i]=true;if(i % prime[j]==0) break; //prime[j]一定是i的最小質因子}}cout<<count1<<endl; }

補充

如何找到第一個大于100000的質數呢?

解答:就是使用試除法判斷質數的方法,從100000開始遍歷,使用標志flag,如果i不是質數,flag=false;如果i是質數,flag=true;然后判斷flag如果等于true,就break跳出循環,輸出i,即為大于100000的最小質數。

#include<bits/stdc++.h> using namespace std;const int maxn=100000;int main(){for(int i=maxn;;i++){bool flag=true;for(int j=2;j<=i/j;j++){if(i%j==0){flag=false;break;}}if(flag){cout<<i<<endl;break;}}} 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的算法刷题-数论-质数的判定、分解质因数、筛质数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。