线性筛素数的实现与证明
情境
大家應該都知道用nlogn的時間復雜度篩出[1,n]的所有素數,但是當n的范圍較大時,這個方法就不奏效了
今天我們談談素數的線性篩法,也就是用On的時間復雜度篩出[1,n]的所有素數
解析
nlog的算法之所以會慢,是因為它進行了很多重復的操作
比如,24可能就被篩了很多遍
那么我們優化復雜度的思路就是嘗試避免這些重復操作
也就是讓每個合數只被篩一次
怎么做呢?
我們讓每個合數只會被自己的最小質因數篩到
先看一下代碼:
代碼
void solve(){for(int i=2;i<=n;i++){if(v[i]==0){//還沒被篩到就是素數了prime[++tot]=i;v[i]=i;}for(int j=1;j<=tot;j++){ll now=prime[j];if(now>v[i]||now*i>n) break;//now*i>n就是超出范圍了,顯然也不要了v[now*i]=now;}}return; }其中:
v[i]數組表示i的最小質因數
prime是素數表
代碼是怎么做的?
枚舉每一個數,再枚舉已有的素數,只要當前素數還不大于自己的最小質因數,就一直用它篩
這個算法可以說是:
巧奪天工
為什么這樣是對的呢?
接下來我們來證明一下這么做為什么就能不重不漏的篩出所有素數
證明
我們要證明兩部分:不重、不漏
不漏
會不會少篩一些合數?
假設有一個合數a,那么它一定有一個不等于它本身的最小質因數
也就是說,存在:
顯然v不會大于k的最小質因數,否則k的那個最小質因數就也是a的最小質因數了
那么我們在代碼中循環枚舉到k時,顯然就會用質數表中已經有的v把a篩出來
不重
考慮反證法
假設代碼過程中存在i與素數now,使得:
且a的最小的質因數比i還小
不妨還設這個最小質因數為v
由于now已經是素數,所以這個v一定是i的一個因數
也就是說i存在一個質因數且小于now
那么now就一定比i的最小質因數大了
就會在前面的判斷中break出去
證畢
總結
以上是生活随笔為你收集整理的线性筛素数的实现与证明的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 臭鼬是什么动物 臭鼬吃什么食物
- 下一篇: 君子可欺之以方什么意思