莫比乌斯反演

update in 2022.11

0.前言

老年退役选手的消遣

1.莫比乌斯函数

\(\mu\)或莫比乌斯函数是指以下函数:

\[\mu(n) = \left\{ \begin{aligned} 1 \quad\qquad\qquad \qquad \qquad \qquad \qquad n = 1 \\ \quad \qquad (-1)^k \qquad n = p_1 p_2...p_k, p_i为互不相同的素数 \\ 0 \quad\qquad\qquad\qquad n含有指数大于1的质因子 \end{aligned} \right. \]

莫比乌斯函数的性质:

性质1:对于任意正整数n:

\[\epsilon(n) = \sum_{d\mid n} \mu(n) = \left\{ \begin{aligned} 1 \qquad n = 1 \\ 0 \qquad n > 1 \end{aligned} \right. \]

性质2:对于任意正整数n:

\[\sum_{d \mid n} \frac{\mu(d)}{d} = \frac{\phi(n)}{n} \]

证明:

即证

\[ n \cdot \sum_{d \mid n}\frac{\mu(d)}{d} = \phi(n) \]

\[左 = n \cdot \sum_{d \mid n}\frac{\mu(d)}{d} = \sum_{d \mid n}\mu(d)\frac{n}{d} = \sum_{d \mid n}\mu(d)Id(\frac{n}{d}) = (\mu * Id)(n)\\ = (\mu * \phi * 1)(n) = (\mu * \phi * \mu^{-1})(n) = (\phi * \epsilon)(n) = \sum_{d \mid n}\phi(d)\epsilon(\frac{n}{d}) = \phi(n) = 右 \]

证毕

性质2推论:

\[\sum_{d \mid n} d\cdot \mu(\frac{n}{d}) = \phi(n) \]

证明: 令\(k = \frac{n}{d}\),带入原式,易得。

线性筛求 \(\mu\)

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);
		}
	}
}

2.莫比乌斯反演

\(f(n), F(n)\) 为定义在正整数集合上的函数。
\(F(n)\) 满足:

\[F(n) = \sum_{d \mid n} f(d) \]

则:

\[f(n) = \sum_{d \mid n} \mu(d)F(\frac{n}{d}) \]

或:

\[f(n) = \sum_{n \mid d} \mu(\frac{d}{n})F(d) \]

前一个式子证明:(使用定义法)

\[右 = \sum_{d \mid n} \mu(d)F(\frac{n}{d}) = \sum_{d \mid n}\mu(d)\cdot \sum_{k \mid \frac{n}{d}}f(k) = \sum_{k \mid n} f(k) \cdot \sum_{d \mid \frac{n}{k}} \mu(d) = f(n) = 左 \]

证毕。(第三个等号看不明白可以代个数算算,可以发现两边正好相等)

也可以使用狄利克雷卷积证明

\[ F(n) = \sum_{d \mid n} f(d) = \sum_{d \mid n}f(d) \cdot 1(\frac{n}{d}) = (f * 1)(n) = (f * \mu^{-1})(n) \]

\[ f(n) = \sum_{d \mid n}f(d) \cdot \epsilon(\frac{n}{d}) = (f * (\mu * \mu^{-1}))(n) = (\mu * (f * \mu^{-1}))(n) \\ = \sum_{d \mid n} \mu(d)(f * \mu^{-1})(\frac{n}{d}) = \sum_{d \mid n} \mu(d) F(\frac{n}{d}) \]

证毕

3.题目:

[HAOI2011]Problem b

求:

\[\sum_{i = a}^{b} \sum_{j = c}^{d}[gcd(i, j) = k] \]

利用二维前缀和将其转化为求

\[\sum_{i = 1}^{n} \sum_{j = 1}^{m}[gcd(i, j) = k] \]

开始推式子:(式子中的除法均为整除)

\[ \begin{aligned} && \sum_{i = 1}^{n} \sum_{j = 1}^{m}[gcd(i, j) = k] && = \sum_{i = 1}^{ \frac{n}{k} } \sum_{j = 1}^{ \frac{m}{k} }[gcd(i, j) = 1] && = \sum_{i = 1}^{ \frac{n}{k}} \sum_{j = 1}^{ \frac{m}{k}} \epsilon(gcd(i, j)) && = \sum_{i = 1}^{ \frac{n}{k} } \sum_{j = 1}^{ \frac{m}{k} } \sum_{d \mid gcd(i, j)} \mu(d) \end{aligned} \]

因为 \(d \mid gcd(i, j)\) 可以表示为同时满足 \(d \mid i, d \mid j\) ,所以

\[\begin{aligned} && 原式 = \sum_{d = 1}^{min(\frac{n}{k}, \frac{m}{k})}\mu(d) \cdot \sum_{d \mid i}^{\frac{n}{k}}\sum_{d \mid j}^{\frac{m}{k}} 1 && = \sum_{d = 1}^{min(\frac{n}{k}, \frac{m}{k})}\mu(d) \cdot \sum_{i = 1}^{\frac{n}{kd}}\sum_{j = 1}^{\frac{m}{kd}} 1 && = \sum_{d = 1}^{min(\frac{n}{k}, \frac{m}{k})}\mu(d) \frac{n}{kd}\frac{m}{kd} \end{aligned} \]

至此,已经可以 \(O(n)\) 求解了。但题目中询问次数很大,所以需要降低每次询问的复杂度。
考虑整除分块,设当前一段区间的左端点为 \(d\) ,则右端点为 \(min(n/(n / d), m / (m / d))\), \(\mu(d)\) 用前缀和实现。

typedef int lld;
const int N = 100005;
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);
		}
	}
	for(int i = 1; i <= n; i++) {
		mu[i] += mu[i - 1];
	}
}
lld a[N], b[N], c[N], d[N], k[N];
lld t, f[N];
lld calc(lld n, lld m, lld k) {
	lld p = min(n / k, m / k), tmp = 0;
	for(lld i = 1; i <= p; ) {
		lld j = min(n / (n / i), m / (m / i));
		if(j > p) break;
		tmp = tmp + (mu[j] - mu[i - 1]) * (n / i / k) * (m / i / k);
		i = j + 1;
	}
	return tmp;
}
int main() {
//	freopen("data.in", "r", stdin);
	int n; scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d%d%d%d%d", &a[i], &b[i], &c[i], &d[i], &k[i]);
		t = max(t, max(b[i], d[i]));
	}
	euler(t);
	for(int i = 1; i <= n; i++) {
		printf("%d\n", calc(b[i], d[i], k[i]) - calc(b[i], c[i] - 1, k[i]) - calc(a[i] - 1, d[i], k[i]) + calc(a[i] - 1, c[i] - 1, k[i]));
	}
	return 0;
}

此题开long long会暴毙。

posted @ 2021-01-16 01:37  Mcggvc  阅读(110)  评论(0编辑  收藏  举报