【笔记】莫比乌斯反演

0 约定

[n]=[1,n]Z

1 数论分块

形如 S(n)=i=1nf(i)g(ni)

可以在 O(n) 的时间复杂度内求解。


1.1 解法

  1. 对于 1in

    显然,i 最多 n 种取值,故而 ni 最多有 n 种取值。

  2. 对于 n<in

    nin,最多亦有 n 种取值。

综上,如果可以 O(1) 得到 f 的区间和,那么可以通过枚举 ni 的取值,O(2n)O(n) 求解。

具体代码如下:

int res = 0;
for (int i = 1, j; i <= n; i = j+1) {
    j = n/(n/i);
    res += (f(j) - f(i-1)) * g(n/i);
}

其中 j 为对于当前 i 满足 ni=nj 的最大的 j


2 莫比乌斯函数

对于一些函数 f(n),如果很难直接求出它的值,而容易求出其倍数和或约数和 g(n),那么可以通过莫比乌斯反演,简化运算得到 f(n) 的值。

2.1 定义

定义莫比乌斯函数:

μ(n)={1n=10n 含有平方因子(1)kk 为 n 的不同质因子个数

注:

  1. 「含有平方因子」是指存在 p 为质数,α 为满足 pα=n 的最大整数,α2。eg. μ(24)=0

2.2 性质

  1. μ(n)不完全 积性函数,即 μ(x)μ(y)=μ(xy) 当且仅当 (x,y)=1

  2. 狄利克雷卷积 相关:

    1. (μI)={1n=10n1=ε

      证明与下类似。

    2. (μId)=φ

      证明:

      设:n=p1α1p2α2pkαkp 为质数,α 为正整数。

      (μId)(n)=d|nμ(d)nd=(μ(1)p1α11+μ(p1)p1α1p1++μ(p1α1)p1α1p1α1)(μ(1)pkαk1+μ(pk)pkαkpk++μ(pkαk)pkαkpkαk)【直接把括号展开,就可以发现她是对的】=(p1α1p1α1p1)(p2α2p2α2p2)(pkαkpkαkpk)【把 μ 的值带进去】=(p11)p1α1p1×(p21)p2α2p2××(pk1)pkαkpk=(p11)p1α11(p21)p2α21(pk1)pkαk1=φ(n)【 φ 的一种公式计算法】


3 求莫比乌斯函数

3.1 O(n)

线性质数筛(欧拉筛)的一大优势在于我们可以知道每个数的 最小质因子,从而通过递推线性求解 积性函数

void init (int _n) {
	for (int i = 2; i <= _n; i++) is_prime[i] = 1;
	mu[1] = 1;
	for (int i = 2; i <= _n; i++) {
		if (is_prime[i])
			prime.push_back(i),
			mu[i] = -1;
		for (int j : prime) {
			if (1ll*i*j > _n) break;
			is_prime[i*j] = 0;
			if (i%j == 0) {
				mu[i*j] = 0;
				break;
			}
			mu[i*j] = -mu[i];
		}
	}
}

3.2 O(nlnn)

mu[1] = 1;
for (int i = 1; i <= n; i++)
    for (int j = i+i; j <= n; j += i)
        mu[j] -= mu[i];

证明是显然的:

d|nμ(d)=[n=1]μ(n)=d|ndnμ(d) when~n>1.


4 莫比乌斯反演

设两个个数论函数 f(x),F(x),若有 F(x)=d|xf(d)

则有:

f(x)=d|xμ(d)F(nd)=d|xμ(nd)F(d)


5 例题

5.1 简单的数学题

5.1.1 Description

已知:n

求:

(i=1nj=1nijgcd(i,j))modp

感性感知一下,gcd(i,j) 的取值实际上很少,所以突破口在于枚举她的取值。

设:

f(d)=i,j[n]gcd(i,j)=dij

F(x)=d|xf(d)

G(x)=i=1ni=n(n+1)2

答案即为 Ans=d=1nf(d)d

下考虑求解 f(d)

F(d)=d|id|jij=d|ii×d|jj=(i=1niid)2=(G(ni)d)2

从而:

Ans=d=1ndi=1niμ(i)F(ix)

推柿子:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int lim = 1e7;
int mu[lim+5], phi[lim+5];
bool is_prime[lim+5];
vector<int> prime;
ll _S[lim+5], inv2, inv6, ans, p, n;
unordered_map<ll, ll> S;
ll qpow (ll a, ll b) {
	ll res = 1;
	for (; b; b >>= 1, (a *= a) %= p)
		if (b & 1) (res *= a) %= p;
	return res;
}
void init (int _n) {
	for (int i = 2; i <= _n; i++) is_prime[i] = 1;
	phi[1] = 1;
	mu[1] = 1;
	for (int i = 2; i <= _n; i++) {
		if (is_prime[i])
			prime.push_back(i),
			phi[i] = i-1,
			mu[i] = -1;
		for (int j : prime) {
			if (1ll*i*j > _n) break;
			is_prime[i*j] = 0;
			if (i%j == 0) {
				phi[i*j] = j * phi[i];
				mu[i*j] = 0;
				break;
			}
			phi[i*j] = phi[j] * phi[i];
			mu[i*j] = -mu[i];
		}
	}
	for (int i = 1; i <= _n; i++)
		_S[i] = (_S[i-1] + 1ll*i*i%p * phi[i]%p) % p;
}
ll F1 (ll x) { return x%=p, x*(x+1)%p*inv2%p; }
ll F2 (ll x) { return x%=p, x*(x+1)%p*(x*2+1)%p*inv6%p; }
ll F3 (ll x) { return x%=p, F1(x) * F1(x) % p; }
ll solve (ll x) {
	if (x <= lim) return _S[x];
	if (S[x]) return S[x];
	ll res = F3(x);
	for (ll i = 2, j; i <= x; i = j+1) {
		j = x/(x/i);
		res = (res - solve(x/i) * (F2(j) - F2(i-1) + p) % p + p) % p;
	}
	return S[x] = res;
}
int main () {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	cin >> p >> n;
	inv2 = qpow(2, p-2), inv6 = qpow(6, p-2);
	init(lim);
	for (ll i = 1, j; i <= n; i = j+1) {
		j = n/(n/i);
		(ans += F1(n/i) * F1(n/i)%p * ((solve(j) - solve(i-1)+p)%p) % p) %= p;
	}
	cout << ans;
	return 0;
}

5.2 【模板】杜教筛


5.3 YY的GCD

posted @   CloudWings  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示