普通筛
任务:筛出 N 以内的所有素数
枚举 2 ~ N 之间素数,把素数的倍数置位false,剩下true的就加入到素数表中。复杂度 O(nlogn) 。
bool isPrime[N];
int prime_tot[N];//从 1 开始存储
void prime_table() //普通筛
{
int cnt = 0;
memset(isPrime,true,sizeof(isPrime));
for(int i = 2; i < N; i++)
{
if(isPrime[i])
{
prime_tot[++cnt]=i;
for(int k = 2; k*i < N; k++ )
isPrime[k*i] = false;
}
}
}
线性筛
可以发现普通筛会出现重复筛,比如 2 会筛 6 一次,3 又筛 6 一次,即每个数都由其全部的因子从小到大来筛;而线性筛是利用每个数的最大真因子负责来筛,复杂度为O(n)。
bool isPrime[N];
int prime_tot[N];
void prime_table() //线性筛
{
int cnt = 0;
memset(isPrime,true,sizeof(isPrime));
for(int i = 2; i < N; i++)
{
if(isPrime[i])
prime_tot[++cnt] = i;
for(int j = 1; j <= cnt && prime_tot[j] * i < N; j++) //筛掉i素数倍的合数
{
isPrime[prime_tot[j] * i] = false;
if(i % prime_tot[j] == 0) //此处重点,倍数不超过 i 的最小素因子
break;
}
}
}
Mobius函数
在线性筛的基础上顺带处理。
bool isPrime[N];
int prime_tot[N];
int mu[N];
void get_mu() //莫比乌斯函数
{
int cnt = 0;
mu[1] = 1; // n == 1
memset(isPrime,true,sizeof(isPrime));
for(int i = 2; i < N; i++)
{
if(isPrime[i])
{
prime_tot[++cnt] = i;
mu[i] = -1; //质数只含一个因子
}
for(int j = 1; j <= cnt && prime_tot[j] * i < N; j++)
{
isPrime[prime_tot[j] * i] = false;
if(i % prime_tot[j] == 0) // i含平方因子
break;
else
mu[prime_tot[j] * i] = -mu[i];
}
}
}
狄利克雷卷积
(看成函数的运算?)
函数运算满足分配率,交换律,结合律,两积性函数的卷积仍是积性函数。
常见的积性函数
- 欧拉函数 φ ( x ) \varphi(x) φ(x)
- 莫比乌斯函数 μ ( x ) \mu(x) μ(x)
- 单位函数 i d ( n ) = n id(n)=n id(n)=n
- 不变函数 1 ( n ) = 1 1(n)=1 1(n)=1
- 狄利克雷卷积单位元
ε
=
[
n
=
=
1
]
\varepsilon=[n ==1]
ε=[n==1]
特别地,有 μ ∗ I = ε \mu *I=\varepsilon μ∗I=ε
欧拉函数 φ ( x ) \varphi(x) φ(x)
- 定义:表示小于等于x的正整数中和x互质的数的个数 。 φ ( 1 ) = 1 \varphi (1)=1 φ(1)=1
- 有一性质:n的所有因子的 phi 值 加起来等于 n。
-
欧拉函数和莫比乌斯函数的关系:
可用狄利克雷卷积证明 -
( φ ∗ I ) ( n ) = i d ( n ) (\varphi*I)(n)=id(n) (φ∗I)(n)=id(n)
-
φ ∗ I ∗ μ = i d ∗ μ \varphi*I*\mu=id*\mu φ∗I∗μ=id∗μ
-
φ ( n ) = ∑ d ∣ n n d ∗ μ ( d ) \varphi(n)=\sum_{d|n}\frac{n}{d}*\mu(d) φ(n)=∑d∣ndn∗μ(d)
莫比乌斯反演两个公式
- g ( n ) = ∑ d ∣ n f ( d ) ⟹ g(n)=\sum_{d|n}f(d)\Longrightarrow g(n)=∑d∣nf(d)⟹ f ( n ) = ∑ d ∣ n μ ( d ) g ( n d ) f(n)=\sum_{d|n}\mu(d)g(\frac{n}{d}) f(n)=∑d∣nμ(d)g(dn)
- g ( n ) = ∑ n ∣ d f ( d ) ⟹ g(n)=\sum_{n|d}f(d)\Longrightarrow g(n)=∑n∣df(d)⟹ f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) f(n)=\sum_{n|d}\mu(\frac{d}{n})g(d) f(n)=∑n∣dμ(nd)g(d)
两个公式证明可参照上方用狄利克雷卷积证明的方法。
分块计算
任务:快速计算
∑
⌊
n
k
⌋
(
1
≤
k
≤
n
)
\sum\lfloor \frac{n}{k} \rfloor (1\le k\le n)
∑⌊kn⌋(1≤k≤n) 复杂度O(
2
n
2\sqrt n
2n)。
背景:
⌊
n
k
⌋
(
1
<
=
k
<
=
n
)
\lfloor \frac{n}{k} \rfloor (1<=k<=n)
⌊kn⌋(1<=k<=n) 有约
2
n
2\sqrt n
2n个互不相同的值,比如 n = 21 ,k =1,2,3,4,5,6-7,8-10,11-21,共8个不同的值。(用笔写写,可以发现左右两边是对称的)
int ans = 0;
for(int l = 1,r; l <= n; l = r+1)
{
r = N / (N / l);
ans += (r-l+1) * (N/l); //区间个数 * 每个数的贡献值
}
杜教筛
任务: ∑ i = 1 n μ ( i ) , n ≤ 1 0 12 \sum_{i=1}^{n}\mu(i),n\le10^{12} ∑i=1nμ(i),n≤1012
在这里插入代码片
太弱了,具体的证明过程可参考巨巨们的链接:
peng_ym
https://blog.youkuaiyun.com/skywalkert/article/details/50500009