( 数论专题 )【 欧拉筛 】
线性筛是一个很基础的算法,但是我一直没学。直到一次考试,因为O(n√n)会超时,用了表筛,结果被卡了代码长度,于是开始学习欧拉筛。
算法思路:
对于每一个数(无论质数合数)x,筛掉所有小于x最小质因子的质数乘以x的数。比如对于77,它分解质因数是7*11,那么筛掉所有小于7的质数*77,筛掉2*77、3*77、5*77。
好吧,是不是听起来太简单了。。。。没事,重点在证明。
算法证明:
首先我们要明确证明思路。如果要证明它是对的,只要保证两点:没用重复筛、没有漏筛
1、没有重复筛。
我们假设一个合数分解成p1*p2*p3,并且保证p1<p2<p3。我们知道,筛掉这个合数的机会有:p1和p2*p3,p2和p1*p3,p3和p1*p2。但我们知道,我们选择的那个质数必须小于那个合数的最小质因子。比如p2和p1*p3,因为p2>p1,所以这样是筛不到的。唯一会筛的是第一种:p1和p2*p3。
2、没有漏筛。
还是假设把这个合数分解质因数a*b*c,保证a<b<c然后我们设s=b*c,s肯定小于刚才那个合数,说明肯定对于它已经筛过,然后a肯定小于s,因为s=b*c,并且a是最小的因子。说明a*s也就是这个合数一定筛过。
证明没看懂的直接看代码吧。。挺好背的。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 2e6+10;
int primes[maxn],cnt;
bool isprime[maxn];
void get_prime()
{
memset(isprime,true,sizeof(isprime));
for ( int i=2; i<=maxn; i++ ) {
if ( isprime[i]==true ) primes[cnt++]=i;
for ( int j=0; j<cnt&&i*primes[j]<=maxn; j++ ) {
isprime[ i*primes[j] ] = false;
if ( i%primes[j]==0 ) break;
}
}
}
signed main()
{
get_prime();
for ( int i=0; i<100; i++ ) cout << primes[i] << " ";
return 0;
}