线性筛集合
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;
}
}
}
}