时间复杂度为O(n)
一般的线性筛选法
prime[0] = false;
prime[1] =false;
for (int i=2; i<N; i++)
{
if (prime[i])
{
primes[++cnt ]=i;
for (int k=i*i; k<N; k+=i)
prime[k]=false;
}
}
#include<iostream>
#include <cstdio>using namespace std;
const int n=200000;
int prime[n]= {0},num_prime=0;
int main()
{
int a[n]= {1,1},i,j;
for(i=2; i<10000; i++)
{
if(!a[i])
prime[num_prime++]=i;
for(j=0; j<num_prime && i*prime[j]<n; j++)
{
a[i*prime[j]]=1;
if(!(i%prime[j]))
break;
}
}
/*
for(i=0; i<100; i++)
{printf("%d\n", prime[i]);
}
*/
return 0;
}
线性筛法,即是筛选掉所有合数,留下质数
我们知道合数可以由一个质数数与另一个数相乘得到 而同时假设合数a=质数b×质数c×一个数d 令e=c × d,假设b ≥ e,e为合数,令f=d × b a=f × c ,其中c<e;
即比一个合数数大的质数和该合数的乘积可用一个更大的合数和比其小的质数相乘得到 这也是if(!( i % prime[j]))break;的含义,这也是线性筛法算质数表的关键所在
/*线性筛O(n)时间复杂度内筛出maxn内欧拉函数值*/
int
m[maxn],phi[maxn],p[maxn],pt;
//m[i]是i的最小素因数,p是素数,pt是素数个数
int
make()
{
phi[1]=1;
int
N=maxn;
int
k;
for
(
int
i=2;i<N;i++)
{
if
(!m[i])
//i是素数
p[pt++]=m[i]=i,phi[i]=i-1;
for
(
int
j=0;j<pt&&(k=p[j]*i)<N;j++)
{
m[k]=p[j];
if
(m[i]==p[j])
//为了保证以后的数不被再筛,要break
{
phi[k]=phi[i]*p[j];
/*这里的phi[k]与phi[i]后面的∏(p[i]-1)/p[i]都一样(m[i]==p[j])只差一个p[j],就可以保证∏(p[i]-1)/p[i]前面也一样了*/
break
;
}
else
phi[k]=phi[i]*(p[j]-1);
//积性函数性质,f(i*k)=f(i)*f(k)
}
}
}