知识点 - 杜教筛

知识点 - 杜教筛

解决问题类型:

积性函数前缀和,

做法是 将原函数和恒等函数卷积得到F,对F求前缀和并使用微扰法求出原函数前缀和。

模板:

//注意mp<int,ll>
//一般很卡常,可以考虑换语言交
ll GetSum(int n) { // 算 f 前缀和的函数
  ll ans = f_g_sum(n); // 算 f * g 的前缀和
  // 以下这个 for 循环是整除分块
  for(ll l = 2, r; l <= n; l = r + 1) { // 注意从 2 开始
    r = (n / (n / l)); 
    ans -= (g_sum(r) - g_sum(l - 1)) * GetSum(n / l);
    // g_sum 是 g 的前缀和
    // 递归 GetSum 求解
  } return ans; 
}

公式推导:

问题:设f(n)为数论函数,求
S ( n ) = ∑ i = 1 n f ( n ) S(n)=\sum_{i=1}^{n} f(n) S(n)=i=1nf(n)
想法:根据 f ( n ) f(n) f(n)的性质,构造一个 S ( n ) S(n) S(n)关于 S ( ⌊ n i ⌋ ) S(\lfloor \frac{n}{i}\rfloor) S(⌊in⌋)的递推式。

构造方法如下:

找到一个合适的 g ( n )   , l e t   F = f ∗ g g(n)\ , \mathrm{let}\ F=f*g g(n) ,let F=fg
F ( n ) = ∑ d ∣ n f ( n d ) g ( d ) F(n)=\sum_{d|n}f(\frac{n}{d})g(d) F(n)=dnf(dn)g(d)
对F求前缀和,则有
∑ F ( n ) = ∑ i = 1 n ∑ d ∣ i f ( i d ) g ( d ) = ∑ d ∣ i ∑ d = 1 n f ( i d ) g ( d ) = ∑ d = 1 n g ( d ) ∑ i = 1 ⌊ n d ⌋ f ( i ) = ∑ d = 1 n g ( d ) S ( ⌊ n d ⌋ ) \sum F(n)=\sum_{i=1}^{n}\sum_{d|i}f(\frac{i}{d})g(d)=\sum_{d|i}\sum_{d=1}^nf(\frac{i}{d})g(d)\\ =\sum_{d=1}^ng(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} f(i)=\sum_{d=1}^{n}g(d)S(\lfloor\frac{n}{d}\rfloor) F(n)=i=1ndif(di)g(d)=did=1nf(di)g(d)=d=1ng(d)i=1dnf(i)=d=1ng(d)S(⌊dn⌋)

∑ i = 1 n ∑ d ∣ i f ( d ) g ( i d ) = ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) \sum_{i=1}^{n}\sum_{d|i}f(d)g(\frac{i}{d})=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\\ i=1ndif(d)g(di)=i=1ng(i)S(⌊in⌋)
提出 g ( 1 ) S ( n ) g(1)S(n) g(1)S(n),移项(即微扰法 perturb the sum)可以得到递推式
g ( 1 ) S ( n ) = ∑ i = 1 n F ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}F(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=i=1nF(i)i=2ng(i)S(⌊in⌋)
注意到后半部分的式子中的 S ( ⌊ n i ⌋ ) S(\lfloor\frac{n}{i}\rfloor) S(⌊in⌋)可以用整除分块 O ( n ) O(\sqrt n) O(n )地求出(见知识点 - 整除分块)。

复杂度

若能够快速求:(具体来说,小于 O ( n ) O(\sqrt{n}) O(n )
∑ i = 1 n ( f ∗ g ) ( i ) , ∑ i = 1 n g ( i ) \sum_{i=1}^{n}(f*g)(i),\sum_{i=1}^{n}g(i) i=1n(fg)(i)i=1ng(i)
那么计算单个S(n)的时间复杂度就变为
T ( n ) = O ( n ) + ∑ i = 1 n ( T ( i ) + T ( n i ) )   T(n)=O(\sqrt{n})+\sum_{i=1}^{\sqrt{n}}{(T(i)+T(\frac{n}{i}))}\\\ \\ T(n)=O(n )+i=1n (T(i)+T(in)) 
展开一阶小量,积分,有
T ( n ) = ∑ i = 1 n O ( i ) + O ( n i ) = O ( n 3 4 ) T(n)=\sum_{i=1}^{\sqrt{n}}{O(\sqrt{i})+O(\sqrt{\frac{n}{i}})}=O(n^\frac{3}{4}) T(n)=i=1n O(i )+O(in )=O(n43)
可以打表预处理来加速,如果线性预处理出了f(n)的前k项 ( k ≥ n ) (k\ge\sqrt{n}) (kn ),此时复杂度变为:
T ( n ) = k + ∑ i = 1 n k n i = O ( n k + k ) T(n)=k+\sum_{i=1}^{\frac{n}{k}}{\sqrt{\frac{n}{i}}}=O(\frac{n}{\sqrt{k}}+k) T(n)=k+i=1knin =O(k n+k)
k = n 2 3 k=n^\frac{2}{3} k=n32时取到最小值 O ( 2 n 2 3 ) O(2n^\frac{2}{3}) O(2n32)

例题1

Φ ( n ) = ∑ i = 1 n φ ( i ) \Phi(n)=\sum_{i=1}^{n}{\varphi(i)} Φ(n)=i=1nφ(i)为欧拉函数前缀和。

解析

利用性质
∑ d ∣ n φ ( d ) = n ⇔ I ∗ φ = i d \sum_{d|n}{\varphi(d)}=n\Leftrightarrow I*\varphi=id dnφ(d)=nIφ=id
所以令 g ( n ) g(n) g(n)为常函数 I ( n ) = 1 I(n)=1 I(n)=1,带入通式
g ( 1 ) S ( n ) = ∑ i = 1 n F ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}F(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\\ g(1)S(n)=i=1nF(i)i=2ng(i)S(⌊in⌋)
得到:
1 ⋅ Φ ( n ) = ∑ i = 1 n i − ∑ i = 2 n 1 ⋅ Φ ( ⌊ n i ⌋ ) 1\cdot \Phi(n)=\sum_{i=1}^{n}i-\sum_{i=2}^{n}1\cdot \Phi(\lfloor\frac{n}{i}\rfloor)\\ 1Φ(n)=i=1nii=2n1Φ(⌊in⌋)
(补充推导:当然也可以从 I ∗ φ = i d I*\varphi=id Iφ=id直接从头推导,有
∴ φ ( n ) = n − ∑ d ∣ n , d < n φ ( d ) \therefore \varphi(n)=n-\sum_{d|n,d<n}{\varphi(d)} φ(n)=ndn,d<nφ(d)
推导得:
ϕ ( n ) = ∑ i = 1 n φ ( i ) = ∑ i = 1 n i − ∑ d ∣ i , d < i φ ( d ) = n ⋅ ( n + 1 ) 2 − ∑ i = 2 n ∑ d ∣ i , d < i φ ( d ) = n ⋅ ( n + 1 ) 2 − ∑ i d = 2 n ∑ d = 1 ⌊ n i d ⌋ φ ( d ) = n ⋅ ( n + 1 ) 2 − ∑ i = 2 n ∑ d = 1 ⌊ n i ⌋ φ ( d ) = n ⋅ ( n + 1 ) 2 − ∑ i = 2 n ϕ ( ⌊ n i ⌋ ) \phi(n)=\sum_{i=1}^{n}{\varphi(i)}=\sum_{i=1}^{n}{i-\sum_{d|i,d<i}{\varphi(d)}}=\frac{n\cdot(n+1)}{2}-\sum_{i=2}^{n}\sum_{d|i,d<i}{\varphi(d)}=\frac{n\cdot(n+1)}{2}-\sum_{\frac{i}{d}=2}^{n}\sum_{d=1}^{\left\lfloor\frac{n}{\frac{i}{d}}\right\rfloor}{\varphi(d)}\\=\frac{n\cdot(n+1)}{2}-\sum_{i=2}^{n}\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}{\varphi(d)}=\frac{n\cdot(n+1)}{2}-\sum_{i=2}^{n}{\phi(\lfloor\frac{n}{i}\rfloor)} ϕ(n)=i=1nφ(i)=i=1nidi,d<iφ(d)=2n(n+1)i=2ndi,d<iφ(d)=2n(n+1)di=2nd=1dinφ(d)=2n(n+1)i=2nd=1inφ(d)=2n(n+1)i=2nϕ(⌊in⌋)

理论分析

具体数学4.9节的做法:

首先对于实数x有结论:
∑ d ≥ 1 Φ ( x d ) = ⌊ x ⌋ ⋅ ⌊ x + 1 ⌋ / 2 w h e r e   Φ ( x ) = Φ ( ⌊ x ⌋ ) \sum_{d\ge1}\Phi(\frac{x}{d})=\lfloor x\rfloor\cdot\lfloor x+1\rfloor/2\\ \mathrm{where\ }\Phi(x)=\Phi(\lfloor x\rfloor) d1Φ(dx)=xx+1/2where Φ(x)=Φ(⌊x⌋)
(微扰法将第1项提出来有
Φ ( x ) = ⌊ x ⌋ ⋅ ⌊ x + 1 ⌋ / 2 − ∑ d ≥ 2 Φ ( ⌊ x d ⌋ ) \Phi(x)=\lfloor x\rfloor\cdot\lfloor x+1\rfloor/2-\sum_{d\ge2}\Phi(\lfloor \frac{x}{d}\rfloor) Φ(x)=xx+1/2d2Φ(⌊dx⌋)
​ 得到杜教筛的递推式。)

第一个式子可以这么理解:可以将右边看成所有 0 ≤ m < n ≤ x 0\le m\lt n\le x 0m<nx的分数 m n \frac{m}{n} nm的(未约分)分数的数量,而左边可以理解为形式为 m n \frac{m}{n} nm g c d ( m , n ) = d \mathrm{gcd}(m,n)=d gcd(m,n)=d的分数的个数为 Φ ( x d ) \Phi(\frac{x}{d}) Φ(dx).

精确推导如下:
n ⋅ ( n + 1 ) 2 = ∑ i = 1 n i = ∑ i = 1 n ∑ d [ d ∣ i ] ⋅ φ ( d ) = ∑ i d = 1 n ∑ d = 1 ⌊ n i d ⌋ φ ( d ) = ∑ i = 1 n ϕ ( ⌊ n i ⌋ ) \frac{n\cdot(n+1)}{2}=\sum_{i=1}^{n}{i}=\sum_{i=1}^{n}\sum_{d}{[d|i]\cdot\varphi(d)}=\sum_{\frac{i}{d}=1}^{n}\sum_{d=1}^{\left\lfloor\frac{n}{\frac{i}{d}}\right\rfloor}{\varphi(d)}=\sum_{i=1}^{n}{\phi(\lfloor\frac{n}{i}\rfloor)} 2n(n+1)=i=1ni=i=1nd[di]φ(d)=di=1nd=1dinφ(d)=i=1nϕ(⌊in⌋)
直接对第一个式子使用莫比乌斯反演变式:
g ( x ) = ∑ d ≥ 1 f ( x / d ) ⇔ f ( x ) = ∑ d ≥ 1 μ ( d ) g ( x / d ) g(x)=\sum_{d\ge1}f(x/d)\Leftrightarrow f(x)=\sum_{d\ge1}\mu(d)g(x/d) g(x)=d1f(x/d)f(x)=d1μ(d)g(x/d)
注意这个变式与原莫比乌斯公式的区别:
g ( n ) = ∑ d ∣ n f ( d ) ⇔ f ( n ) = ∑ d ∣ n g ( n d ) μ ( d ) g(n)=\sum_{d|n}f(d)\Leftrightarrow f(n)=\sum_{d|n}g(\frac{n}{d})\mu(d) g(n)=dnf(d)f(n)=dng(dn)μ(d)
该变式适用于所有
∑ k , d ≥ 1 ∣ f ( x / k d ) ∣ < ∞ \sum_{k,d\ge1}|f(x/kd)|\lt \infty k,d1f(x/kd)<
这里顺便证明一下:
∑ d ≥ 1 μ ( d ) g ( x / d ) = ∑ d ≥ 1 μ ( d ) ∑ k ≥ 1 f ( x / k d )   = ∑ m ≥ 1 f ( x / m ) ∑ k , d ≥ 1 μ ( d ) [ m = k d ]   = ∑ m ≥ 1 f ( x / m ) ∑ d ∣ m μ ( d ) = ∑ m ≥ 1 f ( x / m ) [ m = 1 ] = f ( x ) \sum_{d\ge1}\mu(d)g(x/d)=\sum_{d\ge1}\mu(d)\sum_{k\ge1}f(x/kd)\\\ \\ =\sum_{m\ge1}f(x/m)\sum_{k,d\ge1}\mu(d)[m=kd]\\\ \\ =\sum_{m\ge1}f(x/m)\sum_{d|m}\mu(d)=\sum_{m\ge1}f(x/m)[m=1]=f(x) d1μ(d)g(x/d)=d1μ(d)k1f(x/kd) =m1f(x/m)k,d1μ(d)[m=kd] =m1f(x/m)dmμ(d)=m1f(x/m)[m=1]=f(x)
∑ d ≥ 1 Φ ( x d ) \sum_{d\ge1}\Phi(\frac{x}{d}) d1Φ(dx)用反演,得到
Φ ( x ) = 1 / 2 ∑ d ≥ 1 μ ( d ) ⌊ x / d ⌋ ⋅ ⌊ x / d + 1 ⌋ \Phi(x)=1/2\sum_{d\ge1}\mu(d)\lfloor x/d\rfloor\cdot\lfloor x/d+1\rfloor\\ Φ(x)=1/2d1μ(d)x/dx/d+1
由于 ⌊ x / d ⌋ \lfloor x/d\rfloor x/d前有莫比乌斯函数的系数,无法用整除分块,复杂度依然为O(n)。

不过这个式子可以用来计算近似值:(具体数学ch9中有证明)
Φ ( x ) = 3 / π 2 x 2 + O ( x l o g x ) \Phi(x)=3/\pi^2x^2+O(xlogx) Φ(x)=3/π2x2+O(xlogx)

例题2

求梅滕斯函数 M ( n ) = ∑ i = 1 n μ ( i ) M(n)=\sum_{i=1}^{n}{\mu(i)} M(n)=i=1nμ(i)

解析

利用性质
[ n = 1 ] = ∑ d ∣ n μ ( d ) n ⇔ I ∗ μ = e [n=1]=\sum_{d|n}{\mu(d)} n\Leftrightarrow I*\mu=e [n=1]=dnμ(d)nIμ=e
和上一题同样地,令 g ( n ) g(n) g(n)为常函数 I ( n ) = 1 I(n)=1 I(n)=1,带入通式
g ( 1 ) S ( n ) = ∑ i = 1 n F ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}F(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\\ g(1)S(n)=i=1nF(i)i=2ng(i)S(⌊in⌋)
得到
1 ⋅ M ( n ) = 1 − ∑ i = 2 n 1 ⋅ M ( ⌊ n i ⌋ ) 1\cdot \Mu(n)=1-\sum_{i=2}^{n}1\cdot \Mu(\lfloor\frac{n}{i}\rfloor)\\ 1M(n)=1i=2n1M(⌊in⌋)
(补充推导:
1 = ∑ i = 1 n [ i = 1 ] = ∑ i = 1 n ∑ d ∣ i μ ( d ) = ∑ i = 1 n ∑ d = 1 ⌊ n i ⌋ μ ( d ) = ∑ i = 1 n M ( ⌊ n i ⌋ ) 1=\sum_{i=1}^{n}{[i=1]}=\sum_{i=1}^{n}\sum_{d|i}{\mu(d)}=\sum_{i=1}^{n}\sum_{d=1}^{\lfloor\frac{n}{i}\rfloor}{\mu(d)}=\sum_{i=1}^{n}{M(\lfloor\frac{n}{i}\rfloor)} 1=i=1n[i=1]=i=1ndiμ(d)=i=1nd=1inμ(d)=i=1nM(⌊in⌋)

代码:

P4213 【模板】杜教筛(Sum)

#include<iostream>
#include<map>
#include<string>
#include<cstring>
#include<vector>
#include<algorithm>
#include<set>
#include<sstream>
#include<cstdio>
#include<cmath>
#include<climits>
#include<cstdlib>
#include<iomanip>
#include<unordered_map>
using namespace std;
const double PI = acos(-1.0);

#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define debug(x) cerr<<#x<<":"<<x<<endl
#define pb push_back
#define FAST_IO ios::sync_with_stdio(0); cin.tie(0)
const int maxn = 1e7;
const int N = 3e6;
typedef long long ll;
int mu[N], lp[N], sumu[N];
ll phi[N],sump[N];
vector<int> pr;
void init() {
	mu[1] = 1;
	phi[1] = 1;
	for (int i = 2; i <= N; ++i) {
		if (lp[i] == 0) {
			lp[i] = i;
			mu[i] = -1;
			phi[i] = i - 1;
			pr.push_back(i);
		}
		for (int j = 0; j < (int)pr.size() && pr[j] <= lp[i] && i*pr[j] <= N; ++j)
		{
			lp[i * pr[j]] = pr[j];
			if (i%pr[j])phi[i*pr[j]] = phi[i] * (pr[j] - 1), mu[i * pr[j]] = -mu[i];
			else phi[i*pr[j]] = phi[i] * pr[j];
		}
	}
	sumu[0] = 0;
	sump[0] = 0;
	rep(i, 1, N-1) {
		sumu[i] = sumu[i-1] + mu[i];
		sump[i] = sump[i - 1] + phi[i];
	}
}
unordered_map<int,ll> Smu, Sphi;
inline ll GetSumu(int n) {
	if (n <= N-1) return sumu[n]; // sumu是提前筛好的前缀和
	if (Smu[n]) return Smu[n]; // 记忆化
	ll ret = 1ll; // 单位元的前缀和就是 1
	for (int l = 2, r; l <= n; l = r + 1) {
		r = n / (n / l); ret -= (r - l + 1) * GetSumu(n / l);
		// (r - l + 1) 就是 I 在 [l, r] 的和
	} return Smu[n] = ret; // 记忆化
}
inline ll GetSphi(int n) {
	if (n <= N-1) return sump[n]; // 提前筛好的
	if (Sphi[n]) return Sphi[n]; // 记忆化
	ll ret = 1ll * n * (n + 1) / 2; // f * g = id 的前缀和
	for (int l = 2, r; l <= n; l = r + 1) {
		r = n / (n / l); ret -= (r - l + 1) * GetSphi(n / l);
		// 同上,因为两个的 g 都是 I 
	} return Sphi[n] = ret; // 记忆化
}
int main() {
	init();
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		cout << GetSphi(n) << ' ' << GetSumu(n) << endl;
	}
	int n;
	cin >> n;
}
/*
6
1
2
8
13
30
2333
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Best KeyBoard

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值