从前有一个素数筛法叫埃拉托斯特尼筛法,它的思想很简单,把1-n以内素数的整数倍的数字划掉,留下的就全是素数,但是它的复杂度是O(NlglgN),对于大量不友好数据会跪,于是线性晒登场了。
#include
using namespace std;
int prime[1100000],primesize,phi[11000000];
bool isprime[11000000];
void getlist(int listsize)
{
memset(isprime,1,sizeof(isprime));
isprime[1]=false;
for(int i=2;i<=listsize;i++)
{
if(isprime[i])prime[++primesize]=i;
for(int j=1;j<=primesize&&i*prime[j]<=listsize;j++)
{
isprime[i*prime[j]]=false;
if(i%prime[j]==0)break;
}
}
}
①:if(i%prime[j]==0)break;
这句代码保证了每个数最多被筛一次,将时间复杂度降到了线性。
证明如下:prime[]数组中的素数是递增的,当i能整除prime[j],那么i*prime[j+1]这个合数肯定被prime[j]乘以某个数筛掉。
因为i中含有prime[j],prime[j]比prime[j+1]小,即i=k*prime[j],那么i*prime[j+1]=(k*prime[j])*prime
[j+1]=k’*prime[j],接下去的素数同理。所以不用筛下去了。因此,在满足i%prime[j]==0这个条件之前以及第一次
满足改条件时,prime[j]必定是prime[j]*i的最小因子。
大名鼎鼎的线性晒日常筛素数的速度大概是埃氏筛的3-4倍,然而在小数据中却有被完爆的可能QAQ
所以欧拉筛法不只是拿来筛个素数,更重要的一点是线性筛可以用来求解积性函数。
积性函数f(x)应满足f(a×b)=f(a)×f(b),a与b应互素。而完全积性函数则应满足对于任意的a与b,前面的等式应成立。
先上欧拉phi函数:
memset(check,false,sizeof(check));
fai[1] = 1;
int tot = 0;
for(int i = 2 ; i <= N ; i++)
{
if(! check[i])
{
prime[tot++] = i;
fai[i] = i - 1;
}
for(int j = 0 ; j < tot ; j++)
{
if(i * prime[j] > N) break;
check[i * prime[j]] = true;
if(i % prime[j] == 0){
fai[i * prime[j]] = fai[i] * prime[j];
break;
}
else {
fai[i * prime[j]] = fai[i] * (prime[j] - 1);
}
}
}
再来个线性筛解莫比乌斯函数:
memset(check,false,sizeof(check));
mu[1] = 1;
int tot = 0;
for(int i = 2 ; i <= N ; i++)
{
if(! check[i])
{
prime[tot++] = i;
mu[i] = -1;
}
for(int j = 0 ; j < tot ; j++)
{
if(i * prime[j] > N) break;
check[i * prime[j]] = true;
if(i % prime[j] == 0){
mu[i * prime[j]] = 0;
break;
}
else {
mu[i * prime[j]] = -mu[j];
}
}
}