版权声明: https://blog.csdn.net/qq_38234381/article/details/82946333
线性筛,别名欧拉筛,因可以在O(n)的时间里筛出1-n的素数而得名。
板子:
int cnt, prime[N];
bool is_prime[N];
void euler_sieve() {
memset(is_prime, true, sizeof(is_prime));
int i, j;
for (i=2; i<=n; i++) {
if (is_prime[i]) prime[++cnt]=i;
for (j=1; i*prime[j]<=n; j++) {
is_prime[i*p[j]]=false;
if (i%prime[j]==0) break;
}
}
return ;
}
然后它其实还可以用来求约数个数和约数和。
预备知识:
①我们设d[i]表示i的约数个数,那么d[i*j]=d[i]*d[j],条件是i和j互质,对于约数和的函数也同理。这种函数被称为积性函数。关于积性函数的一些性质:https://baike.baidu.com/item/%E7%A7%AF%E6%80%A7%E5%87%BD%E6%95%B0/8354949?fr=aladdin
②算法基本定理:https://baike.baidu.com/item/%E7%AE%97%E6%9C%AF%E5%9F%BA%E6%9C%AC%E5%AE%9A%E7%90%86#4
关于在线性的时间的里求出d[i],和dk[i]的证明可以看这篇博客:https://blog.csdn.net/controlbear/article/details/77527115
附上代码:
//约数和
void euler_sieve() {
memset(is_prime, true, sizeof(is_prime));
d1[1]=1, d0[1]=1;
for (int i=2; i<=N-10; i++) {
if (is_prime[i]) {
prime[++cnt]=i;
d1[i]=1+i;
d0[i]=1+i;
}
for (int j=1; prime[j]*i<=N-10; j++) {
is_prime[prime[j]*i]=false;
if (i%prime[j]) {
d1[i*prime[j]]=d1[i]*d1[prime[j]];
d0[i*prime[j]]=prime[j]+1;
}
else {
d1[i*prime[j]]=d1[i]/d0[i]*(d0[i]*prime[j]+1);
d0[i*prime[j]]=d0[i]*prime[j]+1;
break;
}
}
}
return ;
}
//约数个数
int d[N], d0[N];
void euler_sieve() {
memset(is_prime, true, sizeof(is_prime));
d[1]=1, d0[1]=0;
for (int i=2; i<=N-10; i++) {
if (is_prime[i]) {
prime[++cnt]=i;
d[i]=2;
d0[i]=1;
}
for (int j=1; prime[j]*i<=N-10; j++) {
is_prime[prime[j]*i]=false;
if (i%prime[j]) {
d[i*prime[j]]=d[i]*d[prime[j]];
d0[i*prime[j]]=1;
}
else {
d[i*prime[j]]=d[i]/(d0[i]+1)*(d0[i]+2);
d0[i*prime[j]]=d0[i]+1;
break;
}
}
}
return ;
}