莫比乌斯反演学习笔记

前言

本文只是作者学习莫比乌斯反演后做的相关笔记,可能并不适合入门。

基础

莫比乌斯函数

\(x=p_1^{\alpha_1}\times p_2^{\alpha_2}\times \dots\times p_k^{\alpha_k}\)

则:

\(\mu(x)=\begin{cases} 1&{x=1} \\ 0&{\alpha_i>1(1\le i\le k)} \\ (-1)^k &\text{otherwise} \end{cases}\)

一个基本性质

\(S(n)=\sum\limits_{d|n}\mu(d)\)

\(S(n)=[n=1]\)

证明略。

一个简单结论

\[[\gcd(i,j)=1]\Leftrightarrow\sum\limits_{d|i, d|j}\mu(d) \]

第一个式子

\[\begin{aligned} &F(n)=\sum\limits_{d|n}f(d) \\ \Rightarrow\ &f(n)=\sum\limits_{d|n}\mu(d)F(\frac{n}{d}) \end{aligned}\]

证明:

\[\begin{aligned} f(n) &= \sum\limits_{d|n}\mu(d)F(\frac{n}{d}) \\ &= \sum\limits_{d|n}\mu(d)\sum\limits_{i|\frac{n}{d}}f(i) \\ &= \sum\limits_{i|n}f(i)\sum\limits_{d|\frac{n}{i}}\mu(d) \\ &= \sum\limits_{i|n}f(i)S(\frac{n}{i}) \\ &= f(n) &&\square \end{aligned}\]

第二个式子

\[\begin{aligned} &F(n)=\sum\limits_{n|d}f(d) \\ \Rightarrow\ &f(n)=\sum\limits_{n|d}\mu(\frac{d}{n})F(d) \end{aligned}\]

证明:

\(d'=\frac{d}{n}\)

\[\begin{aligned} f(n) &= \sum\limits_{n|d}\mu(\frac{d}{n})F(d) \\ &= \sum\limits_{n|d}\mu(\frac{d}{n})\sum\limits_{d|i}f(i) \\ &= \sum\limits_{n|i}f(i)\sum\limits_{d'|\frac{n}{i}}\mu(d') \\ &= \sum\limits_{n|i}f(i)S(\frac{n}{i}) \\ &= f(n) &&\square \end{aligned}\]

值得注意的是,我们在做题中常用的是第二个式子。

例题

[HAOI2011]Problem b

题意:求 \(\sum\limits_{a\le x\le b}\sum\limits_{c\le y\le d}[\gcd(x, y)=k]\)

\(S(a, b)=\sum\limits_{1\le x\le a}\sum\limits_{1\le y\le b}[\gcd(x, y)=k]\)

可以通过二维前缀和的方式转化问题,答案即为 \(S(b,d)-S(a-1,d)-S(b,c-1)+S(a-1,c-1)\)

接下来有两种方法求解。

方法一:

\(n=\lfloor\frac{a}{k}\rfloor\)\(m=\lfloor\frac{b}{k}\rfloor\)

\[\begin{aligned} &\sum\limits_{x=1}^a\sum\limits_{y=1}^b [\gcd(x,y)=k] \\ =&\sum\limits_{x=1}^{n}\sum\limits_{y=1}^{m}[\gcd(x,y)=1] \\ =&\sum\limits_{x=1}^{n}\sum\limits_{y=1}^{m}\sum\limits_{d|\gcd(x,y)}\mu(d) \\ =&\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{d|x,d|y}\mu(d) \\ =&\sum\limits_{d=1}^{\min(n,m)}\mu(d)\sum\limits_{\lfloor\frac{n}{d}\rfloor}\sum\limits_{\lfloor\frac{m}{d}\rfloor}1 \\ =&\sum\limits_{d=1}^{\min(n,m)}\mu(d)\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor \end{aligned}\]

方法二:

\(F(n)=\sum\limits_{x=1}^a\sum\limits_{y=1}^b[n|\gcd(x,y)]=\lfloor\frac{a}{n}\rfloor\lfloor\frac{b}{n}\rfloor\)\(f(n)=\sum\limits_{x=1}^a\sum\limits_{y=1}^b[\gcd(x,y)=n]\)

很显然有:\(F(n)=\sum\limits_{n|d}f(d)\)

莫比乌斯反演得到:\(f(n)=\sum\limits_{n|d}\mu(\frac{d}{n})F(d)\)

\(d'=\frac{d}{n}\)\(a'=\frac{a}{n}\)\(b'=\frac{b}{n}\)

推式子:

\[\begin{aligned} f(n)&=\sum\limits_{n|d}\mu(\frac{d}{n})F(d) \\ &=\sum\limits_{n|d}\mu(\frac{d}{n})\lfloor\frac{a}{n}\rfloor\lfloor\frac{b}{n}\rfloor \\ &=\sum\limits_{d'}\mu(d')\lfloor\frac{a}{d'n}\rfloor\lfloor\frac{b}{d'n}\rfloor \\ &=\sum\limits_{d'}\mu(d')\lfloor\frac{a'}{d'}\rfloor\lfloor\frac{b'}{d'}\rfloor \\ \end{aligned}\]

然后整除分块即可。

代码:

#include <bits/stdc++.h>
#define DEBUG fprintf(stderr, "Passing [%s] line %d\n", __FUNCTION__, __LINE__)
#define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)

using namespace std;

typedef long long LL;
typedef pair <int, int> PII;
typedef pair <int, PII> PIII;

template <typename T>
inline T gi()
{
    T f = 1, x = 0; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return f * x;
}

const int INF = 0x3f3f3f3f, N = 50003, M = N << 1;

int T;
int mu[N], sum[N];
bool isprime[N];
int pri[N], tot;

inline void pre()
{
	mu[1] = 1;
	for (int i = 2; i <= 50000; i+=1)
	{
		if (!isprime[i]) pri[++tot] = i, mu[i] = -1;
		for (int j = 1; j <= tot && 1ll * i * pri[j] <= 50000; j+=1)
		{
			isprime[i * pri[j]] = true;
			if (i % pri[j] == 0) break;
			mu[i * pri[j]] = -mu[i];
		}
	}
	for (int i = 1; i <= 50000; i+=1) sum[i] = sum[i - 1] + mu[i];
}

inline LL S(int a, int b, int k)
{
	a /= k, b /= k;
	int n = min(a, b);
	LL ans = 0;
	for (int l = 1, r; l <= n; l = r + 1)
	{
		r = min(n, min(a / (a / l), b / (b / l)));
		ans = ans + 1ll * (sum[r] - sum[l - 1]) * (a / l) * (b / l);
	}
	return ans;
}

int main()
{
    //File("");
    pre();
    T = gi <int> ();
    while (T--)
    {
    	int a = gi <int> (), b = gi <int> (), 
    		c = gi <int> (), d = gi <int> (), 
    		k = gi <int> ();
    	printf("%lld\n", S(b, d, k) - S(a - 1, d, k) 
    					- S(b, c - 1, k) + S(a - 1, c - 1, k));
    }
    return 0;
}
posted @ 2020-12-27 16:25  csxsi  阅读(76)  评论(0编辑  收藏  举报