【学习笔记】莫比乌斯反演

退役OIer回来受虐啦

一些定义

μ ( x ) = { 1 x = 1 ( − 1 ) n x = ∏ i = 1 n P i 0 o t h e r w i s e \mu(x) = \begin{cases} 1 & x = 1 \\ (-1)^n & x = \prod _ {i=1} ^ {n} P_{i}\\ 0 & otherwise \end{cases} μ(x)= 1(1)n0x=1x=i=1nPiotherwise

φ ( n ) = ∑ i = 1 n   [ g c d ( i , n ) = 1 ] \varphi(n)=\sum_{i=1}^{n}\ [gcd(i,n)=1] φ(n)=i=1n [gcd(i,n)=1]

ε ( n ) =   [ n = 1 ] \varepsilon(n)=\ [n=1] ε(n)= [n=1]

一些性质

∑ d ∣ n μ ( d ) = ε ( n ) \sum_{d|n}\mu(d)=\varepsilon(n) dnμ(d)=ε(n)
μ ∗ 1 = ε \mu\ast1=\varepsilon μ1=ε
推广一下:
[ g c d ( i , j ) = 1 ] = ∑ d ∣ g c d ( i , j ) μ ( d ) [gcd(i,j)=1]=\sum_{d|gcd(i,j)}\mu(d) [gcd(i,j)=1]=dgcd(i,j)μ(d)


φ ∗ 1 = i d \varphi \ast 1=id φ1=id

莫比乌斯变换

f ( n ) = ∑ d ∣ n g ( d )   ⇒   g ( n ) = ∑ d ∣ n f ( d ) μ ( n d ) f(n)=\sum_{d|n} g(d)\ \Rightarrow\ g(n)=\sum_{d|n}f(d)\mu(\frac{n}{d}) f(n)=dng(d)  g(n)=dnf(d)μ(dn)
f ( n ) = ∑ n ∣ d g ( d )   ⇒   g ( n ) = ∑ n ∣ d μ ( d n ) f ( d ) f(n)=\sum_{n|d}g(d)\ \Rightarrow\ g(n)=\sum_{n|d}\mu(\frac{d}{n})f(d) f(n)=ndg(d)  g(n)=ndμ(nd)f(d)

例题

[HAOI2011] Problem b

题目描述

对于给出的 n n n 个询问,每次求有多少个数对 ( x , y ) (x,y) (x,y),满足 a ≤ x ≤ b a \le x \le b axb c ≤ y ≤ d c \le y \le d cyd,且 gcd ⁡ ( x , y ) = k \gcd(x,y) = k gcd(x,y)=k gcd ⁡ ( x , y ) \gcd(x,y) gcd(x,y) 函数为 x x x y y y 的最大公约数。

输入格式

第一行一个整数 n n n,接下来 n n n 行每行五个整数,分别表示 a , b , c , d , k a,b,c,d,k a,b,c,d,k

输出格式

n n n 行,每行一个整数表示满足要求的数对 ( x , y ) (x,y) (x,y) 的个数。

样例 #1

样例输入 #1
2
2 5 1 5 1
1 5 1 5 2
样例输出 #1
14
3

提示

对于 100 % 100\% 100% 的数据满足: 1 ≤ n , k ≤ 5 × 1 0 4 1 \le n,k \le 5 \times 10^4 1n,k5×104 1 ≤ a ≤ b ≤ 5 × 1 0 4 1 \le a \le b \le 5 \times 10^4 1ab5×104 1 ≤ c ≤ d ≤ 5 × 1 0 4 1 \le c \le d \le 5 \times 10^4 1cd5×104

题解

根据容斥原理,原式可以分成 4 块来处理,每一块的式子都为
∑ i = 1 n ∑ j = 1 m [ gcd ⁡ ( i , j ) = k ] \sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)=k] i=1nj=1m[gcd(i,j)=k]
考虑化简该式子

∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ ε ( gcd ⁡ ( i , j ) ) \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\varepsilon(\gcd(i,j)) i=1knj=1kmε(gcd(i,j))
ε \varepsilon ε 函数展开得到

∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ m k ⌋ ∑ d ∣ gcd ⁡ ( i , j ) μ ( d ) \displaystyle\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum_{d\mid \gcd(i,j)}\mu(d) i=1knj=1kmdgcd(i,j)μ(d)
变换求和顺序,先枚举 d ∣ gcd ⁡ ( i , j ) d\mid \gcd(i,j) dgcd(i,j) 可得

∑ d = 1 μ ( d ) ∑ i = 1 ⌊ n k ⌋ [ d ∣ i ] ∑ j = 1 ⌊ m k ⌋ [ d ∣ j ] \displaystyle\sum_{d=1}\mu(d)\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d\mid i]\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d\mid j] d=1μ(d)i=1kn[di]j=1km[dj]
易知 1 ∼ ⌊ n k ⌋ 1\sim\lfloor\dfrac{n}{k}\rfloor 1kn d d d 的倍数有 ⌊ n k d ⌋ \lfloor\dfrac{n}{kd}\rfloor kdn 个,故原式化为

∑ d = 1 min ⁡ ( ⌊ n k ⌋ , ⌊ m k ⌋ ) μ ( d ) ⌊ n k d ⌋ ⌊ m k d ⌋ \displaystyle\sum_{d=1}^{\min(\lfloor \frac{n}{k}\rfloor,\lfloor \frac{m}{k}\rfloor)}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor d=1min(⌊kn,km⌋)μ(d)kdnkdm
整除分块即可求解

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+77;
int mu[N],sum[N];
vector<int> p;
bool bz[N];
void init(int n)
{
	mu[1]=1;
	for(int i=2; i<=n; i++)
	{
		if(!bz[i])
		{
			mu[i]=-1;
			p.push_back(i);
		}
		for(auto j:p)
		{
			if(j*i>n) break;
			bz[i*j]=1;
			if(i%j==0) break;
			else mu[i*j]=-mu[i];
		}
	}
	for(int i=1; i<=n; i++) sum[i]=sum[i-1]+mu[i];
}
int solve(int n,int m,int k)
{
	int ans=0;
	n/=k; m/=k;
	for(int l=1,r; l<=min(n,m); l=r+1)
	{
		r=min((n/(n/l)),(m/(m/l)));
		ans+=(n/l)*(m/l)*(sum[r]-sum[l-1]);
	}
	return ans;
}
void O_o()
{
	int a,b,c,d,k;
	cin>>a>>b>>c>>d>>k;
	cout<<solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k)<<"\n";
}
signed main()
{
	ios::sync_with_stdio(false); cin.tie(0),cout.tie(0);
	
	int T=1;
	init(50000);
	cin>>T;
	while(T--)
	{
		O_o();
	}
}

[国家集训队] Crash的数字表格 / JZPTAB

题目描述

今天的数学课上,Crash 小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数 a a a b b b lcm ( a , b ) \text{lcm}(a,b) lcm(a,b) 表示能同时被 a a a b b b 整除的最小正整数。例如, lcm ( 6 , 8 ) = 24 \text{lcm}(6, 8) = 24 lcm(6,8)=24

回到家后,Crash 还在想着课上学的东西,为了研究最小公倍数,他画了一张 $ n \times m$ 的表格。每个格子里写了一个数字,其中第 i i i 行第 j j j 列的那个格子里写着数为 lcm ( i , j ) \text{lcm}(i, j) lcm(i,j)

看着这个表格,Crash 想到了很多可以思考的问题。不过他最想解决的问题却是一个十分简单的问题:这个表格中所有数的和是多少。当 n n n m m m 很大时,Crash 就束手无策了,因此他找到了聪明的你用程序帮他解决这个问题。由于最终结果可能会很大,Crash 只想知道表格里所有数的和对 20101009 20101009 20101009 取模后的值。

输入格式

输入包含一行两个整数,分别表示 n n n m m m

输出格式

输出一个正整数,表示表格中所有数的和对 20101009 20101009 20101009 取模后的值。

样例 #1

样例输入 #1
4 5
样例输出 #1
122

提示

样例输入输出 1 解释

该表格为:

1 1 1 2 2 2 3 3 3 4 4 4 5 5 5
2 2 2 2 2 2 6 6 6 4 4 4 10 10 10
3 3 3 6 6 6 3 3 3 12 12 12 15 15 15
4 4 4 4 4 4 12 12 12 4 4 4 20 20 20
数据规模与约定
  • 对于 30 % 30\% 30% 的数据,保证 n , m ≤ 1 0 3 n, m \le 10^3 n,m103
  • 对于 70 % 70\% 70% 的数据,保证 n , m ≤ 1 0 5 n, m \le 10^5 n,m105
  • 对于 100 % 100\% 100% 的数据,保证 1 ≤ n , m ≤ 1 0 7 1\le n,m \le 10^7 1n,m107

题解

∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ i = 1 n ∑ j = 1 m i ⋅ j g c d ( i , j ) = ∑ i = 1 n ∑ j = 1 m ∑ d = g c d ( i , j ) i ⋅ j d = ∑ d = 1 m i n ( n , m ) ∑ d ∣ i n ∑ d ∣ j m [ g c d ( i , j ) = d ] i ⋅ j d = ∑ d = 1 m i n ( n , m ) d   ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ [ g c d ( i , j ) = 1 ] i j \sum_{i=1}^{n}\sum_{j=1}^{m} lcm(i,j)\\ =\sum_{i=1}^{n}\sum_{j=1}^{m} \frac{i\cdot j}{gcd(i,j)}\\ =\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d=gcd(i,j)} \frac{i\cdot j}{d}\\ =\sum_{d=1}^{min(n,m)}\sum_{d|i}^{n}\sum_{d|j}^{m} [gcd(i,j)=d]\frac{i\cdot j}{d}\\ =\sum_{d=1}^{min(n,m)}d\ \sum_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sum_{j=1}^{\left\lfloor \frac{m}{d} \right\rfloor} [gcd(i,j)=1]i j i=1nj=1mlcm(i,j)=i=1nj=1mgcd(i,j)ij=i=1nj=1md=gcd(i,j)dij=d=1min(n,m)dindjm[gcd(i,j)=d]dij=d=1min(n,m)d i=1dnj=1dm[gcd(i,j)=1]ij

S ( n , m ) = ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = 1 ] i j S(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m} [gcd(i,j)=1]i j S(n,m)=i=1nj=1m[gcd(i,j)=1]ij

S ( n , m ) = ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = 1 ] i j = ∑ d = 1 n ∑ d ∣ i n ∑ d ∣ j m μ ( d ) ⋅ i ⋅ j = ∑ d = 1 n μ ( d ) ⋅ d 2 ⋅ ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ⋅ j S(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m} [gcd(i,j)=1]i j\\ =\sum_{d=1}^n\sum_{d\mid i}^n\sum_{d\mid j}^m\mu(d)\cdot i\cdot j\\ =\sum_{d=1}^n\mu(d)\cdot d^2\cdot\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}i\cdot j S(n,m)=i=1nj=1m[gcd(i,j)=1]ij=d=1ndindjmμ(d)ij=d=1nμ(d)d2i=1dnj=1dmij

观察上式,前半段可以预处理前缀和;后半段又是一个范围内数对之和,记

g ( n , m ) = ∑ i = 1 n ∑ j = 1 m i ⋅ j = n ⋅ ( n + 1 ) 2 × m ⋅ ( m + 1 ) 2 g(n,m)=\sum_{i=1}^n\sum_{j=1}^m i\cdot j=\frac{n\cdot(n+1)}{2}\times\frac{m\cdot(m+1)}{2} g(n,m)=i=1nj=1mij=2n(n+1)×2m(m+1)
可以 Θ ( 1 ) \Theta(1) Θ(1) 求解

不过这玩意要整除分块套整除分块,而且细节不少

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+7,mod=20101009;
int mu[N],sum[N];
vector<int> p;
bool bz[N];
int Sum(int x, int y)
{
	return ((x*(x+1)/2%mod)*(y*(y+1)/2%mod))%mod;
}
void init(int n)
{
	mu[1]=1;
	for(int i=2; i<=n; i++)
	{
		if(!bz[i])
		{
			mu[i]=-1;
			p.push_back(i);
		}
		for(auto j:p)
		{
			if(j*i>n) break;
			bz[i*j]=1;
			if(i%j==0) break;
			else mu[i*j]=-mu[i];
		}
	}
	for(int i=1; i<=n; i++) sum[i]=(sum[i-1]+mu[i]*i*i%mod)%mod;
}
int S(int n,int m)
{
	int ans=0;
	for(int l=1,r; l<=min(n,m); l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		(ans+=Sum(n/l,m/l)%mod*(sum[r]-sum[l-1])%mod)%=mod;
	}
	return ans;
}
void O_o()
{
	int n,m,ans=0;
	cin>>n>>m;
	init(n);
	for(int l=1,r; l<=min(n,m); l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		(ans+=((r-l+1)*(l+r)/2)%mod*S(n/l,m/l)%mod)%=mod;
	}
	cout<<(ans+mod)%mod;
}
signed main()
{
	ios::sync_with_stdio(false); cin.tie(0),cout.tie(0);
	
	int T=1;
	
//	cin>>T;
	while(T--)
	{
		O_o();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值