莫比乌斯反演学习笔记

0.前置知识

一些函数

  1. (1(n)=1)
  2. (id(n)=n)
  3. (sigma(n))(n)的约数和

狄利克雷卷积

定义两个数论函数运算(*)

(h=f*g),则

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

它满足一些性质:

  1. (f*g=g*f)

  2. (f*(g*h)=(f*g)*h)

    因为(sum_{(ij)k=n}(f(i)g(j))h(k)=sum_{i(jk)=n}f(i)(g(j)h(k)))

  3. ((f+g)*h=f*h+g*h)

  4. ((xf)*g=x(f*g))

  5. 设单位元(epsilon(n) = [n = 1]),则(epsilon*f=f)

  6. 对于每个(f(1) eq 0)的函数(f),存在逆元(g)使得(f*g=epsilon)

如何求一个函数的逆元呢?

(g(n))满足以下式子:

[g(n)=frac 1{f(1)}left(epsilon(n)-sum_{i|n,i eq1}f(i)g(frac ni) ight) ]

这样的话:

[sum_{i|n}f(i)g(frac ni) \ =f(1)g(n) + sum_{i|n, i eq 1} f(i)g(frac ni) \ =epsilon(n) \ herefore f*g=epsilon ]

1.莫比乌斯反演

定义一个函数(mu)使得(mu*1=epsilon)

这样的话,如果(g*1=f),则(f*mu=g)

即:如果(f(n)=sum_{d|n}g(d)),则(g(n)=sum_{d|n}mu(d)f(frac nd))

是不是很简单

2.题目

(n<m)求:

#1

[sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=1] ]

(f=epsilon)(ecause epsilon=1*mu,; herefore g=mu)

于是原式变为:

[sum_{i=1}^nsum_{j=1}^msum_{d|i,d|j}mu(d) \ =sum_{d=1}^n mu(d)sum_{i=1}^nsum_{j=1}^m[d|i][d|j] \ =sum_{d=1}^n mu(d)left[frac nd ight]left[frac md ight] ]

预处理(mu),数论分块就可以(O(sqrt n))求了

#2

[sum_{i=1}^nsum_{j=1}^m gcd(i,j) ]

(f=id)(ecause id=1*varphi,; herefore g=varphi)

于是原式变为:

[sum_{d=1}^nvarphi(d)left[frac nd ight]left[frac md ight] ]

#3

[sum_{i=1}^nsum_{j=1}^msigma(gcd(i,j)) ]

(f=sigma)(ecausesigma=1*(mu*sigma),; herefore g=mu*sigma)

于是原式变为:

[sum_{d=1}^ng(d)left[frac nd ight]left[frac md ight] ]

因为积性函数可以线性筛,所以也可以预处理

#4

[sum_{i=1}^nsum_{j=1}^mf(gcd(i,j)) ]

(g=mu*f),如果我们能预处理出(f),那么可以这样求(g)

(当然是蒯的啦)

void get_g_1(int N, const int *f, int *g)
{
	for (int i = 1; i <= N; i++) g[i] = 0;
	for (int i = 1; i <= N; i++)
		for (int j = 1; i * j <= N; j++)
			g[i * j] = (g[i * j] + mu[i] * f[j]) % mod;
} // 依照定义,O(nlogn)

void get_g_2(int N, const int *f, int *g)
{
	for (int i = 1; i <= N; i++) g[i] = f[i];
	for (int i = 1; i <= N; i++)
		for (int j = 2; i * j <= N; j++)
			g[i * j] = (g[i * j] - g[i]) % mod;
} // 类似求狄利克雷卷积逆的方式,不需要线性筛 mu ,O(nlogn)

void get_g_3(int N, const int *f, int *g)
{
	for (int i = 1; i <= N; i++) g[i] = f[i];
	for (int i = 0; i < prime_count; i++)
		for (int j = N / prime[i]; j >= 1; j--)
			g[j * prime[i]] = (g[j * prime[i]] - g[j]) % mod;
} // Magic! O(nloglogn)

于是原式变为:

[sum_{d=1}^ng(d)left[frac nd ight]left[frac md ight] ]

原文地址:https://www.cnblogs.com/cj-xxz/p/10182999.html