杜教筛学习笔记

杜教筛学习笔记

杜教筛可以在非线性时间 \(O(n^{\frac 23})\) 内快速求出积性函数的前缀和

前置知识

积性函数

积性函数:对 \(\forall a,b\in Z\and gcd(a,b)==1\)\(f(a\cdot b)=f(a)\cdot f(b)\) 的数论函数 \(f\).

完全积性函数:对 \(\forall a,b\in Z\)\(f(a\cdot b)=f(a)\cdot f(b)\) 的数论函数 \(f\).

积性函数举例:\(\varphi,\mu,d,\sigma,\sigma^k\)

完全积性函数举例:\(1,id,id^k,\varepsilon\)

Dirichlet 卷积

数论函数 \(f\)\(g\)\(Dirichlet\) 卷积为:

\[(f*g)(x)=\displaystyle\sum_{d_1\cdot d_2=x}f(d_1)\cdot g(d_2) \]

数论分块

对于含有 \(\lfloor\frac{n}{i}\rfloor(n为常数)\) 的求和式,观察式子的性质

\(\lfloor\frac{n}{i}\rfloor\) 为非严格单调递减数列,且存在多个数值相等的区间 \([l,r]\)

满足 \(\lfloor\frac{n}{i}\rfloor=\lfloor\frac{n}{j}\rfloor,(i,j\in[l,r])\)

对任意 \(i\),可求得其对应的区间右端点 \(r=\left\lfloor{\dfrac{n}{\left\lfloor{\dfrac{n}{i}}\right\rfloor}}\right\rfloor\)

在求和时可以考虑同时求出数值相等区间的总和

采用双指针的思想,设变量 \(l,r\) 为此区间的左右端点

即可通过计算得出,每个区间对应的 \(l,r\)

以便于进行统计答案

复杂度分析

给定 \(n\),求解 \(\displaystyle \sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor,n\in N\)

  • \(i\leq\lfloor\sqrt{n}\rfloor\) 时,\(\lfloor\frac{n}{i}\rfloor\) 有最多 \(\lfloor\sqrt{n}\rfloor\) 种取值
  • \(i\leq\lfloor\sqrt{n}\rfloor\) 时,\(\lfloor\frac{n}{i}\rfloor\leq \lfloor\sqrt{n}\rfloor\)\(\lfloor\frac{n}{i}\rfloor\) 最多有 \(\lfloor\sqrt{n}\rfloor\) 种取值

复杂度 \(O(\sqrt{n})\).

int calc(int n) {
	int res = 0;
	for(int l = 1, r; l <= n; l = r + 1) {
		r = n / (n / l);
		res += (n / l) * (r - l + 1);
	}
	return res;
} 

方法

假设当前需求解 \(f\) 的前缀和 \(S\),即求解

\[S(n)=\displaystyle\sum_{i=1}^nf(i) \]

若直接求解 \(S\) 的复杂度比较高,考虑对 \(f\) 进行卷积运算后 进行前缀和运算

\[\begin{aligned}\displaystyle\sum_{i=1}^n(f*g)(i)&=\sum_{i=1}^n\sum_{d|i}f(\frac id)\cdot g(d)\\&=\sum_{d=1}^n\sum_{\frac id=1}^{\lfloor\frac nd\rfloor}f(\frac id)\cdot g(d)\\&=\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac nd\rfloor}f(i)\cdot g(d)\\&=\sum_{d=1}^ng(d)\sum_{i=1}^{\lfloor\frac nd\rfloor}f(i)\\&=\sum_{d=1}^ng(d)\cdot S(\lfloor\frac nd\rfloor)\\&=g(1)\cdot S(n)+\sum_{d=2}^ng(d)\cdot S(\lfloor\frac nd\rfloor)\end{aligned} \]

移项,系数化 \(1\) 可得

\[S(n)=\frac{\displaystyle\sum_{i=1}^n(f*g)(i)-\sum_{d=2}^ng(d)\cdot S(\lfloor\frac nd\rfloor)}{g(1)} \]

观察式子可得,求解 \(S(n)\) 需保证可以快速求出 \(f*g\) 的前缀和

而分子上 后一部分可以通过 数论分块 来优化解决

应用

莫比乌斯函数前缀和

\[S(n)=\displaystyle \sum_{i=1}^{n}\mu(i)(n<2^{31}) \]

\(f=\mu,g=1\),由 \(Dirichlet\) 卷积可得 \(f*g=\mu*1=\varepsilon\)

\[\begin{aligned} g(1)\cdot S(n)&=\displaystyle\sum_{i=1}^n (f*g)(i)-\sum_{i=2}^n g(i)\cdot S(\lfloor\frac{n}{i}\rfloor)\\1\cdot S(n)&=\sum_{i=1}^n \varepsilon(i)-\sum_{i=2}^n 1\cdot S(\lfloor\frac{n}{i}\rfloor)\\S(n)&=1-\sum_{i=2}^n S(\lfloor\frac{n}{i}\rfloor) \end{aligned} \]

由数论分块可得,\(\lfloor\frac{n}{i}\rfloor\) 的取值有 \(O(\sqrt{n})\) 个,时间复杂度为 \(O(\sum\limits_{i=1}2^{\frac{1}{2^i}}) \approx O(n^{\frac{3}{4}})\).

考虑优化时间复杂度,对于数据较小的部分,直接 \(O(n)\) 线性筛筛出

数据较大的部分则由杜教筛筛出,并采用 记忆化 优化时间复杂度

设线性筛预处理出 \(k\) 个数,余下的 \(n-k\) 个则由杜教筛筛出

时间复杂度为 \(O(k+(n-k)^{\frac{3}{4}})\)

\(k=(n-k)^{\frac{3}{4}}\) 时,时间复杂度取最小值,约为 \(O(n^{\frac{2}{3}})\).

欧拉函数前缀和

\[S(n)=\displaystyle \sum_{i=1}^{n}\varphi(i)(n<2^{31}) \]

\(f=\varphi,g=1\),由 \(Dirichlet\) 卷积可得 \(f*g=\varphi*1=id\)

\[\begin{aligned} g(1)\cdot S(n)&=\displaystyle\sum_{i=1}^n (f*g)(i)-\sum_{i=2}^n g(i)\cdot S(\lfloor\frac{n}{i}\rfloor)\\1\cdot S(n)&=\sum_{i=1}^n id(i)-\sum_{i=2}^n 1\cdot S(\lfloor\frac{n}{i}\rfloor)\\S(n)&=\frac{n^2+n}{2}-\sum_{i=2}^n S(\lfloor\frac{n}{i}\rfloor) \end{aligned} \]

同之前的方法,对于小数据线性筛预处理,大数据杜教筛记忆化

时间复杂度 \(O(n^{\frac{2}{3}})\).

例题:P4213 【模板】杜教筛(Sum)

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int N = 6e6 + 5;
typedef long long LL;
int read() {
	int x = 0, f = 1; char ch;
	while(! isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 3) + (x << 1) + (ch ^ 48));
	return x * f;
}
template <class T> T Max(T a, T b) { return a > b ? a : b; }
template <class T> T Min(T a, T b) { return a < b ? a : b; }
bool vis[N];
int n, cnt, pri[N], sphi[N], smu[N];
map <int, int> mpmu, mpphi;
inline void calc(int x) {
	smu[1] = sphi[1] = 1;
	for(int i = 2; i <= x; ++ i) {
		if(vis[i] == 0) pri[++ cnt] = i, smu[i] = -1, sphi[i] = i - 1;
		for(int j = 1; j <= cnt && i * pri[j] <= x; ++ j) {
			vis[i * pri[j]] = 1;
			if(i % pri[j] == 0) {
				sphi[i * pri[j]] = sphi[i] * pri[j];
				break;
			}
			else smu[i * pri[j]] = - smu[i], sphi[i * pri[j]] = sphi[i] * (pri[j] - 1);
		}
	}
	for(int i = 1; i <= 6e6; ++ i) smu[i] += smu[i - 1], sphi[i] += sphi[i - 1];
}
int sumphi(int n) {
	if(n <= 6e6) return sphi[n];
	if(mpphi[n]) return mpphi[n];
	int res = n * (n + 1) / 2;
	for(int i = 2, j; i <= n; i = j + 1) {
		j = n / (n / i);
		res -= sumphi(n / i) * (j - i + 1);
	}
	return mpphi[n] = res;
}
int summu(int n) {
	if(n <= 6e6) return smu[n];
	if(mpmu[n]) return mpmu[n];
	int res = 1;
	for(LL i = 2, j; i <= n; i = j + 1) {
		j = n / (n / i);
		res -= summu(n / i) * (j - i + 1);
	}
	return mpmu[n] = res;
}
void solve() {
	scanf("%lld", &n);
	printf("%lld %lld\n", sumphi(n), summu(n));
}
signed main() {
	int T = read(); calc(6e6);
	while(T --> 0) solve();
	return 0;
}

莫比乌斯函数的平方值前缀和

\[S(n)=\displaystyle \sum_{i=1}^{n}\mu^2(i)(n<2^{31}) \]

\(f=\mu^2,g=1\),由 \(Dirichlet\) 卷积可得 \(f*g=\mu^2*1=\mu\)

\[\begin{aligned} g(1)\cdot S(n)&=\displaystyle\sum_{i=1}^n (f*g)(i)-\sum_{i=2}^n g(i)\cdot S(\lfloor\frac{n}{i}\rfloor)\\1\cdot S(n)&=\sum_{i=1}^n \mu(i)-\sum_{i=2}^n 1\cdot S(\lfloor\frac{n}{i}\rfloor)\\S(n)&=\sum_{i=1}^n \mu(i)-\sum_{i=2}^n S(\lfloor\frac{n}{i}\rfloor) \end{aligned} \]

在求 \(S(n)\) 过程中,要处理出莫比乌斯函数 \(\mu\) 的前缀和,同样采用杜教筛

时间复杂度 \(O(n^{\frac{2}{3}})\).

莫比乌斯函数值的平方前缀和

\[S(n)=\displaystyle \sum_{i=1}^{n}\mu(i)^2(n<2^{31}) \]

\(f(i)=\mu(i)^2\),寻找合适的 \(g(i)\) 使得 \(f*g\) 的前缀和方便被求出

\(g(x)=[x=k^2],\ k\in N^+\),则有 \(f*g=1\)

证明:

\[(f*g)(n)=\displaystyle\sum_{d_1\cdot d_2=n}f(d_1)\cdot g(d_2) \]

  • \(d_2\) 为完全平方数:只有当 \(d_2\)\(n\) 约数中最大的完全平方数时

    \(f(d_1)\cdot g(d_2)\) 才为 \(1\),否则 \(\mu(d_1)=0\)

  • \(d_2\) 不是完全平方数:\(g(d_2)=0\)

\(\therefore\ f*g=1\)

\[\begin{aligned} g(1)\cdot S(n)&=\displaystyle\sum_{i=1}^n (f*g)(i)-\sum_{i=2}^n g(i)\cdot S(\lfloor\frac{n}{i}\rfloor)\\1\cdot S(n)&=\sum_{i=1}^n 1-\sum_{i=2}^{\sqrt{n}} 1\cdot S(\lfloor\frac{n}{i^2}\rfloor)\\S(n)&=n-\sum_{i=2}^{\sqrt{n}} S(\lfloor\frac{n}{i^2}\rfloor) \end{aligned} \]

时间复杂度:\(O(n^{\frac{2}{3}})\).

posted @ 2022-01-01 23:54  计网君  阅读(118)  评论(0)    收藏  举报