线性筛的一些应用

版权声明: 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 ;
}

猜你喜欢

转载自blog.csdn.net/qq_38234381/article/details/82946333