线性筛素数的实现与证明

60 篇文章 0 订阅
54 篇文章 0 订阅

情境

大家应该都知道用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,那么它一定有一个不等于它本身的最小质因数
也就是说,存在:

a=v*k(v为质数且v<k)

显然v不会大于k的最小质因数,否则k的那个最小质因数就也是a的最小质因数了
那么我们在代码中循环枚举到k时,显然就会用质数表中已经有的v把a筛出来

不重

考虑反证法
假设代码过程中存在i与素数now,使得:

now*i=a;

且a的最小的质因数比i还小
不妨还设这个最小质因数为v
由于now已经是素数,所以这个v一定是i的一个因数
也就是说i存在一个质因数且小于now
那么now就一定比i的最小质因数大了
就会在前面的判断中break出去
证毕

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值