Forever Young

「笔记」Dirichlet卷积

莫比乌斯反演的前置知识

定义

\(f,g\)是数论函数,考虑数论函数\(h\)满足

\[h(n)=\sum_{d|n}f(d)g(\frac{n}{d}) \]

则称\(h\)\(f\)\(g\)的狄利克雷卷积,记作\(h=f*g\),这里的\(*\)表示卷积。

比如\(h(6)=f(1)*g(6)+f(2)*g(3)+f(3)*g(2)+f(6)*g(1)\)

性质

  1. 单位函数\(\epsilon\)是狄利克雷卷积的单位元,即对于任意函数\(f\),有\(\epsilon*f=f*\epsilon=f\)
  2. 狄利克雷卷积满足交换律和结合律。
  3. 如果\(f,g\)都是积性函数,那么\(f*g\)也是积性函数。

许多关系都可以用狄利克雷卷积来表示。

下面用\(1\)来表示取值恒为\(1\)的常函数,定义幂函数\(\text{Id}_{k}(n)=n^k,\text{Id=Id}_1\)

除数函数的定义可以写为:

\[\sigma_k=1*\text{Id}_k \]

欧拉函数的性质可以写为:

\[\text{Id}=\varphi*1 \]

计算狄利克雷卷积

\(f,g\)是数论函数,计算\(f\)\(g\)的狄利克雷卷积在\(n\)处的值需要枚举\(n\)的所有约数。

如果要计算\(f\)\(g\)的狄利克雷卷积的前\(n\)项,可以枚举\(1\)\(n\)中每个数的倍数,根据调和数的相关结论,这样做的复杂度是\(O(n\log n)\)

求函数的逆

狄利克雷卷积有一个性质:对每个\(f(1)\neq0\)的函数\(f\),都存在一个函数\(g\)使得 \(f\ast g=\epsilon\)

那么我们如何求出一个函数的逆呢?

只需要定义:

\[g(n)=\frac 1{ f(1)}\left([n=1]-\sum\limits_{i\mid n, i\neq1} f(i) g\left(\frac ni\right)\right) \]

这样的话

\[\begin{aligned}&\quad\sum_{i\mid n} f(i) g\left(\frac ni\right)\\&= f(1) g(n)+\sum_{i\mid n,i\neq1} f(i) g\left(\frac ni\right)\\&=[n=1]\end{aligned} \]

最后一步直接把\(g(n)\)的定义带进去就好

\[= f(1)*\frac{1}{ f(1)}([n = 1] - \sum\limits_{i|n,i\neq1} f(i) g(\frac n i))+ \sum\limits_{i|n,i\neq1} f(i) g(\frac ni) \]

例题

P2303 [SDOI2012]Longge的问题

给定正整数\(n\),求

\[\sum_{i=1}^{n}gcd(i,n),n\leq2^{32} \]


枚举\(\text{gcd}\)

\[\begin{align*} \sum_{i=1}^{n}gcd(i,n) &= \sum_{d|n}d\sum_{i=1}^{n}[gcd(i,n)=d] \\ &= \sum_{d|n}d\sum_{i=1}^{\frac{n}{d}}[gcd(i,\frac{n}{d})=1] \\ &= \sum_{d|n}d\varphi(\frac{n}{d}) \end{align*}\]

枚举\(n\)的约数直接求。答案是积性的。

#include <cmath> 
#include <cstdio>
#include <cstring> 
#include <iostream>
#define int long long
using namespace std;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1; 
	for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, ans;

int euler(int x) {
	int ans = x, rt = sqrt(x);
	for (int i = 2; i <= rt; i++) {
		if (x % i == 0) {
			ans = ans - ans / i;
			while (x % i == 0) x /= i;
		}
	}
	if (x > 1) ans = ans - ans / x;
	return ans;
}

signed main() {
	n = read();
	int x = sqrt(n);
	for (int i = 1; i <= x; i++) {
		if (n % i == 0) {
			ans += euler(n / i) * i;
			if (i * i != n) ans += euler(i) * (n / i);
		}
	}
	cout << ans << '\n';
	return 0;
}
posted @ 2020-04-27 11:00  Loceaner  阅读(1200)  评论(2编辑  收藏  举报