各种线性筛板子

线性筛集合

1.线性筛素数

lld p[N];
void euler(int n) {
	bool vis[N]; memset(vis, 0, sizeof(vis));
	for(int i = 2; i <= n; i++) {
		if(!vis[i]) {
			vis[i] = true; p[++tot] = i;
		}
		for(int j = 1; i * p[j] <= n && j <= tot; j++) {
			vis[i * p[j]] = true;
		}
	}
}

2.线性筛欧拉函数 (phi)

根据 (phi(n)) 的性质:

1.当n为质数时,(phi(n) = n - 1)

2.若m,n互质,(phi(n cdot m) = phi(n) cdot phi(m))

3.若m为质数,(phi(n cdot m) = phi(n) cdot m)

lld phi[N];
void euler(lld n) {
	bool vis[N]; memset(vis, 0, sizeof(vis));
	lld p[N]; memset(p, 0, sizeof(p));
	int tot = 0; phi[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(!vis[i]) {
			vis[i] = true;
			p[++tot] = i; phi[i] = i - 1;
		}
		for(int j = 1; j <= tot && p[j] * i <= n; j++) {
			vis[p[j] * i] = true;
			if(i % p[j] != 0) phi[i * p[j]] = phi[i] * phi[p[j]];
			else {
				phi[i * p[j]] = phi[i] * p[j]; break;
			}
		}
	}
}

一个关于欧拉函数的小性质:
定义 (f(n)) 为小于等于n的数中,与n互质的所有数的和,则:
(f(n) = frac{phi(n) cdot n}{2})

证明:(gcd(n, i) = gcd(n, n - i))

3.线性筛莫比乌斯函数 (mu)

根据 (mu(n)) 性质:

1.(mu(1) = 1)

2.当n是k个不同素数之积时,(mu(n) = (-1)^k)

3.当n存在指数大于1的质因子时,(mu(n) = 0)

lld mu[N];
void euler(lld n) {
	lld p[N]; memset(p, 0, sizeof(p));
	bool vis[N]; memset(vis, 0, sizeof(vis));
	mu[1] = 1; int tot = 0;
	for(int i = 2; i <= n; i++) {
		if(!vis[i]) {
			p[++tot] = i; vis[i] = true;
			mu[i] = -1;
		}
		for(int j = 1; j <= tot && p[j] * i <= n; j++) {
			vis[p[j] * i] = true;
			if(i % p[j] == 0) mu[i * p[j]] = 0;
			else mu[i * p[j]] = mu[i] * (-1);
		}
	}
}

4.线性筛约数个数

(d(i)) 表示i的约数个数,(las(i)) 表示i最小的质因子的指数
设i为任意一个数,(p[j]) 为已筛出的质数

1.若i为质数,则(d(i) = 2, las(2) = 1)

2.当 (i mod p[j] != 0)时,(d(i cdot p[j]) = d(i) cdot d(p[j]), las(i cdot p[j]) = 1)

3.当 (i mod p[j] = 0)时, (d(i cdot p[j]) = d(i)/(las(i) + 1) * (las(i) + 2)),

(las(i cdot p[j]) = las(i) + 1)

void euler(){
	memset(vis, 0, sizeof(vis)); d[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(!vis[i]) {
			vis[i] = true; p[++tot] = i;
			d[i] = 2; las[i] = 1;
		}
		for(int j = 1; j <= tot && i * p[j] <= n; j++){
			vis[i * p[j]] = true;
			if(i % p[j] == 0){
				d[i * p[j]] = d[i] / (las[i] + 1) * (las[i] + 2);
				las[i * p[j]] = las[i] + 1; break;
			}
			else{
				d[i * p[j]] = d[i] * d[p[j]];
				las[i * p[j]] = 1;
			}
		}
	}
}

5.线性筛约数和

已知:(sd(i) = (1 + p_1 + p_1^2 +...+p_1^{r_1}) cdot (1 + p_2 + p_2^2 +...+p_2^{r_2}) cdot ... cdot (1 + p_k + p_k^2 +...+p_k^{r_k}))

(sd(i)) 表示i的约数和,(num(i)) 表示最小的一项 ((1 + p_1 + p_1^2 +...+p_1^{r_1}))

1.若i为质数,(sd(i) = i + 1, num(i) = i + 1)

2.若 (i mod p[j] != 0), (sd(i cdot p[j]) = sd(i) cdot sd(p[j]), num(i cdot p[j]) = 1 + p[j])

3.若 (i mod p[j] = 0), (sd(i cdot p[j]) = sd(i) / num(i) cdot (num(i) cdot p[j] + 1), num(i cdot p[j]) = num(i) cdot p[j] + 1)

void euler() {
	bool vis[N]; memset(vis, 0, sizeof(vis));
	lld p[N]; memset(p, 0, sizeof(p));
	int tot = 0; num[1] = 1; sd[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(!vis[i]) {
			vis[i] = true; p[++tot] = i;
			num[i] = 1 + i; sd[i] = 1 + i;
		}
		for(int j = 1; j <= tot && p[j] * i <= n; j++) {
			vis[i * p[j]] = true;
			if(i % p[j] != 0) {
				sd[i * p[j]] = sd[i] * sd[p[j]]; num[i * p[j]] = p[j] + 1;
			} else {
				num[i * p[j]] = num[i] * p[j] + 1;
				sd[i * p[j]] = sd[i] / num[i] * num[i * p[j]];
				break;
			}
		}
	}
}

原文地址:https://www.cnblogs.com/mcggvc/p/14306005.html