MITE 质数

6 篇文章 0 订阅

这是MITE的第一篇文章,当然是搞一个最水的东西啦

来自百度的解释:

质数(prime number)又称素数,有无限个。

质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数

 

说到质数,今年下半年大家肯定会想到暴力的方法,就是这个O(n)的办法

bool is_prime(int x)
{
	if(x<2)return 0;
	for(int i=2;i<x;i++)
		if(x%i==0)
			return 0;
	return 1;
}

当然,只要学个编程的同学都知道有个更好的方法,O(\sqrt{x})就能解决问题

bool is_prime(int x)
{
	if(x<2)return 0;
	for(int i=2;i*i<=x;i++)
		if(x%i==0)
			return 0;
	return 1;
}

听起来这个方法很好了对于int里的每个数字判断都可以了,但是,大多数题目不可能只让你求一个素数,你经常要求很多个数字

比如输入n个数字,每个数字小于n,n的范围为1e6,那这题一个个求的话复杂度就为O(n \sqrt {n}),听起来就很不妥对吧。

这时,很多聪明的小伙伴们就想到了打表对吧,对于质数x,x*p(p为正整数)肯定不是质数,于是就有了以下这个代码

int prime[N]

void is_prime(int n)
{
	for(int i=2;i<=n;i++) prime[i]=1;
	for(int i=2;i<=n;i++)
		if(prime[i])
			for(int j=2;i*j<=n;j++)
				prime[i*j]=0;
}

当然这个方法是有名字的,叫做埃拉托斯特尼筛法,一般我们就他埃筛

这个的复杂度为O(n ln ln n),至于为什么嘛

至于调和级数的证明,自己百度吧。

反正我们就这样有个这样的一个方法,其实这个方法还可以优化

int prime(int n)
{
	for(int i=2;i<=n;i++) prime[i]=1;
	for(int i=2;i*i<=n;i++)
		if(prime[i])
			for(int j=i*i;j<=n;j+=i)
				prime[j]=0;
}

我个人认为如果除去初始化后这个的速度甚至不比下面所说的方法慢,但如果是要把质数都记录下来的话当然是下面这个方法快的。

对于埃筛来说,其实还是做了很多无用功,比如21,它先被3搞了一次,又被7ntr了。但这时有些聪明的人就会问了,对于优化后的埃筛来21说不是不会被7ntr嘛,好吧,可能是我举例不够恰当,那就说210吧,这个就很明了吧,对于这种情况,纯爱党们肯定是十分不乐意看到的,大家都不希望自己喜爱的角色被ntr吧,于是就想出了一个办法,总所周知,每一个合数都可以分解为n个质数之积(这根本就不是总所周知啊喂!!),这样的话只要保证每个数都只被最小的质数扫过就行了吧。于是线筛就出生了。

int p[N],tot;
bool prime[N];
int is_prime()
{
	for(int i=2;i<=n;i++)
		prime[i]=1;
	for(int i=2;i<=n;i++)
	{
		if(prime[i]) p[tot++]=i;
		for(int j=0;j<tot && p[j]<=n;j++)
		{
			prime[i*p[j]]=0;
			if(i%p[j]==0)break;
		}
	}
}

p用来记录哪些数是质数的,这个大家都懂,重点还是第三个for,p[i]*i的数不是质因数这个大家都懂,但i%p[j]==0时,这个p[j]是i的最小的质因数,所以i*p[j]的最小的质因数肯定为p[j],这时候就可以停下来了,因为只要继续往后,i的倍数一定会被p[j]扫到,就不用后面的质数来凑热闹了(只要前面还有路,就不要停下来吖)。

这样说可能不太好理解吧,比如说2吧,i是2的倍数,如果我们没在2的时候停下来(不要停下来吖),我们把3*i判定为质数,我们肯定会在i到3*i之间找到一个数p,使2*p==3*i,这是显然存在的,因为i可以表示为2*u,就有2*p==2*(3*u),这样的话就不是纯爱了就被扫了不止一遍。

所以,线筛就保证了每个数都只被自己最小的质因数扫到,所以复杂度为O(n)。

其实大多数情况下写埃筛就很好了,个人认为。

埃筛在处理因数分解上还有奇效,这个自己去发掘把。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值