好久没打博客了。。。。_ (:зゝ∠) _,毕竟狗出竞赛。。。
最近题目都涉及到素数的问题,发现自己连个线筛都不会,赶紧去看了一波。虽说一下子就看懂了。
正题
一般遇到个数,要判断是否为素数。
这从刚学时就开始了。。。。
方法一:
从2~n-1枚举,看是否有一个i使得n%i==0,没有即为素数。
时间O(n)最蠢的
方法二:
从2~sqrt(n)里枚举。因为若存在一个大于sqrt(n)的数能整除n,n/sqrt(n)一定是一个<=sqrt(n)的数,所以在前面一定会被枚举到。
时间O( n√ ).
还有什么其他的“米勒拉宾素数测试的方法”根本就不会,不理它了。
然而现实中并不一定只让你求一个素数,而是让你求一堆的素数。
这时常用的办法为:筛法
方法一:Eratosthenes筛法
如果一个数是素数,那它的倍数就不是素数,对此进行筛法。
memset(bz,true,sizeof(bz));
fo(i,2,n)
if (bz[i]){
fo(j,2,n/i) bz[i*j]=false;
}
速度为O(n* log log n)。
但是其中比如6会在2,3时都被筛一次,就是冗余情况,浪费了时间。
方法二(important):欧拉筛法(线性筛法)
上面的筛法中,时间浪费在一个数会被多个数筛去。
那我们就保证对于一个数x,我们用它最小的质因数i去筛掉它,就可以达到O(n)的速度。
实现为:我们现在枚举到一个素数x,我们就从之前找到素数表里素数i,然后用它们去筛掉数x*i。当x%i==0时,就停止筛选。可以证明,这样就可以保证每个数只会被筛一次。(证明很多人写,就不写了)。
(空想一下,设n1=x* i1,n2=x* i2(i1 < i2),若x%i1==0的话,那n2%i1==0,这样n2就可以用i1去筛)。
fo(i,2,sum) {
if (!bz[i]) pri[++num]=i;
fo(j,1,num){
if (pri[j]*i>sum) break;
bz[pri[j]*i]=true;
if (i%pri[j]==0) break;
}
}
时间为O(n),很快的。
借此筛法,我们可以求欧拉函数了!
欧拉函数:用 ϕ(x)