一.莫比乌斯函数:
1.定义:
μ ( d ) = { 1 , d = 1 ( − 1 ) k , d = p 1 ∗ p 2 ∗ . . . ∗ p k , p 1 , p 2 , . . . 均为互异质数 0 , 其他情况 \mu(d)= \begin{cases} 1, & \text {$d=1$} \\ (-1)^k, & \text{$d=p_1*p_2*...*p_k\;,\;p_1,p_2,...$均为互异质数} \\ 0,& \text{其他情况} \end{cases} μ(d)=⎩⎪⎨⎪⎧1,(−1)k,0,d=1d=p1∗p2∗...∗pk,p1,p2,...均为互异质数其他情况
2.性质:
(1) 积性函数,即如果满足 a a a 和 b b b 互质,那么就会满足 f ( a ∗ b ) = f ( a ) ∗ f ( b ) f(a*b)=f(a)*f(b) f(a∗b)=f(a)∗f(b);
(2) 对任意的正整数
n
n
n ,当
n
>
1
n>1
n>1时,其所有因子的莫比乌斯函数值相加为0,
即:
∑
d
∣
n
μ
(
d
)
=
{
1
,
n
=
1
0
,
n
>
1
\sum_{d|n}{\mu(d)}=\begin{cases} 1,&\ n=1 \\ 0,& \ n>1 \end{cases}
d∣n∑μ(d)={1,0, n=1 n>1
证明:
当
n
=
1
n=1
n=1 时,显然成立;
当
n
>
1
n>1
n>1 时,
首先,有:
μ
(
d
)
≠
0
⟺
d
=
p
1
∗
p
2
∗
.
.
.
∗
p
k
\mu(d) \neq 0\Longleftrightarrow d=p_1*p_2* ... *p_k
μ(d)=0⟺d=p1∗p2∗...∗pk
对于
μ
(
d
)
=
0
\mu(d)=0
μ(d)=0 的因子,我们可以不用考虑,下面仅对
μ
(
d
)
≠
0
\mu(d)\neq 0
μ(d)=0 的因子讨论。
那么对于一个含有
r
r
r 的质因子的因子
d
d
d,
μ
(
d
)
=
C
k
r
∗
(
−
1
)
r
\mu(d)=C_k^r*(-1)^r
μ(d)=Ckr∗(−1)r。
所以
∑
d
∣
n
μ
(
d
)
=
∑
i
=
0
k
C
k
i
∗
(
−
1
)
i
\sum_{d|n}{\mu(d)}=\sum_{i=0}^{k}{C_k^i*(-1)^i}
d∣n∑μ(d)=i=0∑kCki∗(−1)i
又根据二项式定理:
(
x
+
y
)
n
=
∑
i
=
0
n
C
n
i
∗
x
i
∗
y
n
−
i
(x+y)^n=\sum_{i=0}^n{C_n^i*x^i*y^{n-i}}
(x+y)n=i=0∑nCni∗xi∗yn−i
令
x
=
−
1
,
y
=
1
x=-1,y=1
x=−1,y=1,有
∑
i
=
0
k
C
k
i
∗
(
−
1
)
i
=
∑
i
=
0
k
C
k
i
∗
x
i
∗
y
k
−
i
=
0
\sum_{i=0}^{k}{C_k^i*(-1)^i}=\sum_{i=0}^k{C_k^i*x^i*y^{k-i}}=0
i=0∑kCki∗(−1)i=i=0∑kCki∗xi∗yk−i=0
所以,
∑
d
∣
n
μ
(
d
)
=
0
\sum_{d|n}{\mu(d)}=0
d∣n∑μ(d)=0
即证。
(3) 对任意正整数
n
n
n ,有:
∑
d
∣
n
μ
(
d
)
d
=
φ
(
n
)
n
\sum_{d|n}{\frac{\mu(d)}{d}}=\frac{\varphi(n)}{n}
d∣n∑dμ(d)=nφ(n)
证明:
先证:
n
=
∑
d
∣
n
φ
(
d
)
n=\sum_{d|n}{\varphi(d)}
n=d∣n∑φ(d)
令:
f
(
n
)
=
∑
d
∣
n
φ
(
d
)
f(n)=\sum_{d|n}{\varphi(d)}
f(n)=d∣n∑φ(d)
有:
f
(
n
)
∗
f
(
m
)
=
∑
i
∣
n
φ
(
i
)
∗
∑
j
∣
m
φ
(
j
)
f(n)*f(m)=\sum_{i|n}{\varphi(i)}*\sum_{j|m}{\varphi(j)}
f(n)∗f(m)=i∣n∑φ(i)∗j∣m∑φ(j)
=
∑
i
∣
n
∑
j
∣
m
φ
(
i
)
∗
φ
(
j
)
=\sum_{i|n}{\sum_{j|m}\varphi(i)*\varphi(j)}
=i∣n∑j∣m∑φ(i)∗φ(j)
因为欧拉函数为积性函数,所以:
=
∑
i
∣
n
∑
j
∣
m
φ
(
i
∗
j
)
=\sum_{i|n}{\sum_{j|m}{\varphi(i*j)}}
=i∣n∑j∣m∑φ(i∗j)
=
∑
d
∣
n
m
φ
(
d
)
=\sum_{d|nm}{\varphi(d)}
=d∣nm∑φ(d)
=
f
(
n
∗
m
)
=f(n*m)
=f(n∗m)
所以
f
(
n
)
f(n)
f(n) 是积性函数。
根据唯一分解定理:
n
=
p
1
a
1
∗
p
2
a
2
∗
.
.
.
∗
p
k
a
k
n=p_1^{a_1}*p_2^{a_2}*...*p_k^{a_k}
n=p1a1∗p2a2∗...∗pkak
所以:
f
(
n
)
=
f
(
p
1
a
1
∗
p
2
a
2
∗
.
.
.
∗
p
k
a
k
)
=
f
(
p
1
a
1
)
∗
f
(
p
2
a
2
)
∗
.
.
.
∗
f
(
p
k
a
k
)
f(n)=f(p_1^{a_1}*p_2^{a_2}*...*p_k^{a_k})=f(p_1^{a_1})*f(p_2^{a_2})*...*f(p_k^{a_k})
f(n)=f(p1a1∗p2a2∗...∗pkak)=f(p1a1)∗f(p2a2)∗...∗f(pkak)
根据定义,有:
f
(
p
a
)
=
φ
(
1
)
+
φ
(
p
)
+
φ
(
p
2
)
+
.
.
+
φ
(
p
a
)
f(p^{a})=\varphi(1)+\varphi(p)+\varphi(p^2)+..+\varphi(p^{a})
f(pa)=φ(1)+φ(p)+φ(p2)+..+φ(pa)
由欧拉函数性质,当
n
=
p
k
n=p^k
n=pk (
p
p
p 为素数),
φ
(
n
)
=
p
k
−
p
k
−
1
\varphi(n)=p^k-p^{k-1}
φ(n)=pk−pk−1,有:
f
(
p
a
)
=
1
+
(
p
−
1
)
+
(
p
2
−
p
)
+
.
.
.
+
(
p
a
−
p
a
−
1
)
=
p
a
f(p^a)=1+(p-1)+(p^2-p)+...+(p^a-p^{a-1})=p^a
f(pa)=1+(p−1)+(p2−p)+...+(pa−pa−1)=pa
所以:
f
(
n
)
=
p
1
a
1
∗
p
2
a
2
∗
.
.
.
∗
p
k
a
k
=
n
f(n)=p_1^{a_1}*p_2^{a_2}*...*p_k^{a_k}=n
f(n)=p1a1∗p2a2∗...∗pkak=n
所以
n
=
∑
d
∣
n
φ
(
d
)
n=\sum_{d|n}{\varphi(d)}
n=d∣n∑φ(d)
知道这个后,就可以证明性质
(
3
)
(3)
(3) 了。
令
F
(
n
)
=
n
,
f
(
n
)
=
φ
(
n
)
F(n)=n,f(n)=\varphi(n)
F(n)=n,f(n)=φ(n),
所以,
F
(
n
)
=
∑
d
∣
n
f
(
d
)
F(n)=\sum_{d|n}{f(d)}
F(n)=d∣n∑f(d)
很明显符合莫比乌斯反演的约数形式,
反演得:
f
(
n
)
=
∑
d
∣
n
μ
(
d
)
F
(
n
d
)
=
∑
d
∣
n
μ
(
d
)
∗
n
d
f(n)=\sum_{d|n}{\mu(d)F(\frac{n}{d})}=\sum_{d|n}{\mu(d)*\frac{n}{d}}
f(n)=d∣n∑μ(d)F(dn)=d∣n∑μ(d)∗dn
所以:
f
(
n
)
=
n
∗
∑
d
∣
n
μ
(
d
)
d
f(n)=n*\sum_{d|n}{\frac{\mu(d)}{d}}
f(n)=n∗d∣n∑dμ(d)
即:
∑
d
∣
n
μ
(
d
)
d
=
φ
(
n
)
n
\sum_{d|n}{\frac{\mu(d)}{d}}=\frac{\varphi(n)}{n}
d∣n∑dμ(d)=nφ(n)
证毕。
3.线性筛法(基于欧拉筛)
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
vector<int>prime;
int mob[N];
bool vis[N];
void mobius()
{
prime.clear();
memset(vis,0,sizeof(vis));
mob[1]=1;//莫比乌斯函数第一类情况
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime.push_back(i);
mob[i]=-1;//素数
}
for(int j=0;j<prime.size()&&prime[j]*i<N;j++)
{
int tmp=i*prime[j];
vis[tmp]=1;
if(i%prime[j]==0)
{
mob[tmp]=0;//其他情况,因为prime[j]是i的因子,所以k的因子中含有的prime[j]的个数不是1
break;
}
else
mob[tmp]=-mob[i];//积性函数的性质
}
}
}
int main()
{
mobius();
for(int i=1;i<=10;i++)
cout<<mob[i]<<endl;
return 0;
}
二.莫比乌斯反演:
当一个函数 F ( n ) F(n) F(n) 很好求时,而其可以写成其 约数 或 倍数 d d d 的函数 f ( d ) f(d) f(d), f ( d ) f(d) f(d) 很不好求时,我们可以通过莫比乌斯反演利用 F ( n ) F(n) F(n) 反推 f ( d ) f(d) f(d),从而快速求解 f ( d ) f(d) f(d)。
F ( n ) F(n) F(n) 和 f ( n ) f(n) f(n) 是定义在非负整数集合上的两个函数。注意 n n n 和 d d d 不要弄混。
1.约数形式:
F ( n ) = ∑ d ∣ n f ( d ) ⟹ f ( n ) = ∑ d ∣ n μ ( d ) ∗ F ( n d ) F(n)=\sum_{d|n}{f(d)} \Longrightarrow f(n)=\sum_{d|n}{\mu(d)*F(\frac{n}{d})} F(n)=d∣n∑f(d)⟹f(n)=d∣n∑μ(d)∗F(dn)
证明:
∑ d ∣ n μ ( d ) ∗ F ( n d ) = ∑ d ∣ n μ ( d ) ∗ ∑ k ∣ n d f ( k ) \sum_{d|n}{\mu(d)*F(\frac{n}{d})}= \sum_{d|n}{\mu(d)*\sum_{k|\frac{n}{d}}{f(k)}} ∑d∣nμ(d)∗F(dn)=∑d∣nμ(d)∗∑k∣dnf(k)
= ∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) =\sum_{k|n}{f(k) \sum_{d|\frac{n}{k}}{\mu(d)}} =∑k∣nf(k)∑d∣knμ(d) = f ( n ) =f(n) =f(n)
( k 和 d 是 等 价 的 , 原 来 是 一 个 μ ( d ) 对 应 多 个 f ( k ) , 现 在 是 一 个 f ( k ) 对 应 多 个 μ ( d ) ) (k和d是等价的,原来是一个\mu(d)对应多个f(k),现在是一个f(k)对应多个\mu(d)) (k和d是等价的,原来是一个μ(d)对应多个f(k),现在是一个f(k)对应多个μ(d))
对于 ∑ d ∣ n k μ ( d ) \sum_{d|\frac{n}{k}}{\mu(d)} ∑d∣knμ(d) ,由莫比乌斯函数的性质,当且仅 n k = 1 \frac{n}{k}=1 kn=1 时,其值等于1,否则等于0。
2.倍数形式:
F ( n ) = ∑ n ∣ d f ( d ) ⟹ f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) F(n)=\sum_{n|d}{f(d)} \Longrightarrow f(n)=\sum_{n|d}{\mu(\frac{d}{n})F(d)} F(n)=n∣d∑f(d)⟹f(n)=n∣d∑μ(nd)F(d)
证明(同理):
令 k = d n k=\frac{d}{n} k=nd,
∑ n ∣ d μ ( d n ) F ( d ) \sum_{n|d}{\mu(\frac{d}{n})F(d)} ∑n∣dμ(nd)F(d)
= ∑ k = 1 + ∞ μ ( k ) F ( n ∗ k ) =\sum_{k=1}^{+\infty}{\mu(k)F(n*k)} =∑k=1+∞μ(k)F(n∗k)
= ∑ k = 1 + ∞ μ ( k ) ∑ n k ∣ t f ( t ) =\sum_{k=1}^{+\infty}{\mu(k)\sum_{nk|t}{f(t)}} =∑k=1+∞μ(k)∑nk∣tf(t)
= ∑ n ∣ t f ( t ) ∑ k ∣ t n μ ( k ) = f ( n ) = \sum_{n|t}{f(t)}\sum_{k|\frac{t}{n}}{\mu(k)}=f(n) =∑n∣tf(t)∑k∣ntμ(k)=f(n)
三.常见应用:
1. g c d ( i , j ) gcd(i,j) gcd(i,j) 相关问题:
一般先将其转化为求 ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = = 1 ] \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==1] ∑i=1n∑j=1m[gcd(i,j)==1] ,然后利用数论分块解决。
求解 ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = = 1 ] \sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==1] ∑i=1n∑j=1m[gcd(i,j)==1] 的过程:
令 f ( d ) = ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = = d ] , n u m = m i n ( n , m ) f(d)=\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==d]}}, num=min(n,m) f(d)=∑i=1n∑j=1m[gcd(i,j)==d],num=min(n,m)
令 F ( d ) = f ( d ) + f ( 2 d ) + f ( 3 d ) + . . . + f ( k d ) = ∑ d ∣ n n u m f ( n ) F(d)=f(d)+f(2d)+f(3d)+...+f(kd)=\sum_{d|n}^{num}{f(n)} F(d)=f(d)+f(2d)+f(3d)+...+f(kd)=∑d∣nnumf(n)
即 F ( d ) F(d) F(d) 表示 g c d ( i , j ) gcd(i,j) gcd(i,j) 为 d d d 的倍数的二元组的个数,显然 F ( d ) = ⌊ n d ⌋ ∗ ⌊ m d ⌋ F(d)=\lfloor\frac{n}{d}\rfloor* \lfloor\frac{m}{d}\rfloor F(d)=⌊dn⌋∗⌊dm⌋,容易求得。这样就可以通过 F ( d ) F(d) F(d) 来求 f ( d ) f(d) f(d)了。
由反演公式,得:
f ( d ) = ∑ d ∣ n n u m μ ( n d ) F ( n ) = ∑ d ∣ n n u m μ ( n d ) ∗ ⌊ n n ⌋ ∗ ⌊ m n ⌋ f(d)=\sum_{d|n}^{num}{\mu(\frac{n}{d})F(n)}=\sum_{d|n}^{num}{\mu(\frac{n}{d})*\lfloor \frac{n}{n}\rfloor *\lfloor \frac{m}{n}\rfloor} f(d)=∑d∣nnumμ(dn)F(n)=∑d∣nnumμ(dn)∗⌊nn⌋∗⌊nm⌋
(向下取整括号中,上面的 n , m n,m n,m 是范围,下面的 n n n 是变量,注意区分)
当 d = 1 d=1 d=1时,有:(记住)
f ( 1 ) = ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = = 1 ] = ∑ i = 1 m i n ( n , m ) μ ( i ) ∗ ⌊ n i ⌋ ∗ ⌊ m i ⌋ f(1)=\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==1]}}=\sum_{i=1}^{min(n,m)}{\mu(i)*\lfloor \frac{n}{i} \rfloor *\lfloor \frac{m}{i} \rfloor} f(1)=∑i=1n∑j=1m[gcd(i,j)==1]=∑i=1min(n,m)μ(i)∗⌊in⌋∗⌊im⌋
先预处理出莫比乌斯函数的前缀和,然后用数论分块处理。
重点【反演解题套路】:
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=
∑
d
∣
i
,
d
∣
j
μ
(
d
)
[gcd(i,j)=1]=\sum_{d|gcd(i,j)}{\mu(d)}=\sum_{d|i,d|j}{\mu(d)}
[gcd(i,j)=1]=d∣gcd(i,j)∑μ(d)=d∣i,d∣j∑μ(d)
常见应用过程:
∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = 1 ] \sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)=1]}} ∑i=1n∑j=1m[gcd(i,j)=1]
= ∑ i = 1 n ∑ j = 1 m ∑ d ∣ i , d ∣ j μ ( d ) =\sum_{i=1}^{n}{\sum_{j=1}^{m}{\sum_{d|i,d|j}{\mu(d)}}} =∑i=1n∑j=1m∑d∣i,d∣jμ(d)
= ∑ d = 1 m i n ( n , m ) μ ( d ) ∗ ⌊ n d ⌋ ∗ ⌊ m d ⌋ =\sum_{d=1}^{min(n,m)}{\mu(d)*\lfloor \frac{n}{d} \rfloor *\lfloor\frac{m}{d}}\rfloor =∑d=1min(n,m)μ(d)∗⌊dn⌋∗⌊dm⌋(改变枚举顺序)
证明:
因为莫比乌斯函数性质
(
2
)
(2)
(2):
[
n
=
1
]
=
∑
d
∣
n
μ
(
d
)
[n=1]=\sum_{d|n}{\mu(d)}
[n=1]=d∣n∑μ(d)
问题:
1.求 ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] ( n ≤ m ) \sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)=d]}}(n\leq m) ∑i=1n∑j=1m[gcd(i,j)=d](n≤m)
A N S = ∑ i = 1 n ∑ j = 1 m ∑ d ∣ g c d ( i , j ) μ ( d ) = ∑ i = 1 n ∑ j = 1 m ∑ d ∣ i , d ∣ j μ ( d ) ANS=\sum_{i=1}^{n}{\sum_{j=1}^{m}{\sum_{d|gcd(i,j)}{\mu(d)}}}=\sum_{i=1}^{n}{\sum_{j=1}^{m}{\sum_{d|i,d|j}{\mu(d)}}} ANS=∑i=1n∑j=1m∑d∣gcd(i,j)μ(d)=∑i=1n∑j=1m∑d∣i,d∣jμ(d)
= ∑ d = 1 n ( μ ( d ) ∗ ⌊ n d ⌋ ∗ ⌊ m d ⌋ ) =\sum_{d=1}^{n}{(\mu(d)*\lfloor \frac{n}{d}\rfloor*\lfloor \frac{m}{d}\rfloor)} =∑d=1n(μ(d)∗⌊dn⌋∗⌊dm⌋)(改变枚举顺序,常用的技巧)
四.例题:
1.hdu1695:
先附上一篇详解和思路
主要是利用莫比乌斯反演的性质来构造函数,同时利用了莫比乌斯反演的第二个函数关系。还有思维的转化。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int mu[N];
bool vis[N];
vector<int>prime;
void mobius()
{
memset(mu,0,sizeof(mu));
memset(vis,0,sizeof(vis));
prime.clear();
mu[1]=1;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime.push_back(i);
mu[i]=-1;
}
for(int j=0;j<prime.size()&&i*prime[j]<N;j++)
{
int tmp=i*prime[j];
vis[tmp]=1;
if(i%prime[j]==0)
{
mu[tmp]=0;
break;
}
else
mu[tmp]=-mu[i];
}
}
}
int main()
{
int T,cas=0;
mobius();
scanf("%d",&T);
while(T--)
{
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("Case %d: ",++cas);
if(k==0)
{
puts("0");
continue;
}
b/=k;
d/=k;
long long ans1=0,ans2=0;
for(int i=1;i<=min(b,d);i++)
ans1+=(long long)mu[i]*(b/i)*(d/i);
for(int i=1;i<=min(b,d);i++)
ans2+=(long long)mu[i]*(min(b,d)/i)*(min(b,d)/i);
printf("%lld\n",ans1-ans2/2);
}
return 0;
}
2.hdu6390:
欧拉函数的性质+莫比乌斯函数性质的运用
已知:
求:
推导:
一直tle,把数据类型改了一下,竟然就过了,玄学。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,m;
ll p,ans;
ll c[N],inv[N];
int prime[N];
bool vis[N];
int mu[N],phi[N];
void mobius_euler()
{
memset(vis,0,sizeof(vis));
mu[1]=1;
phi[1]=1;
int cnt=0;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime[++cnt]=i;
mu[i]=-1;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*prime[j]<N;j++)
{
int tmp=i*prime[j];
vis[tmp]=1;
if(i%prime[j]==0)
{
mu[tmp]=0;
phi[tmp]=phi[i]*prime[j];
break;
}
else
{
mu[tmp]=-mu[i];
phi[tmp]=phi[i]*phi[prime[j]];
}
}
}
}
void init()
{
inv[1]=1;
for(int i=2;i<=min(n,m);i++)//递推求逆元
inv[i]=inv[p%i]*(ll)(p-p/i)%p;
for(int i=1;i<=min(n,m);i++)
c[i]=(ll)i*inv[phi[i]]%p;
}
ll g(int x,int y)
{
ll res=0;
for(int i=1;i<=min(x,y);i++)
res=(res+(ll)mu[i]*(x/i)*(y/i))%p;
return res;
}
int main()
{
int t;
scanf("%d",&t);
mobius_euler();
while(t--)
{
scanf("%d%d%lld",&m,&n,&p);
ans=0;
init();
for(int i=1;i<=min(n,m);i++)
ans=(ans+c[i]*g(m/i,n/i))%p;
printf("%lld\n",ans);
}
return 0;
}
3.bzoj 2301:【莫比乌斯反演+容斥】
#include <bits/stdc++.h>
using namespace std;
const int N=5e4+5;
vector<int>prime;
bool vis[N];
int mu[N],sum[N];
void mobius()
{
memset(vis,0,sizeof(vis));
memset(mu,0,sizeof(mu));
memset(sum,0,sizeof(sum));
prime.clear();
mu[1]=1;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime.push_back(i);
mu[i]=-1;
}
for(int j=0;j<prime.size()&&i*prime[j]<N;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
mu[i*prime[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=min(n,m),res=0;
for(int l=1,r=1;l<=k;l=r+1)
{
r=min(k,min(n/(n/l),m/(m/l)));
res+=(sum[r]-sum[l-1])*(n/l)*(m/l);
}
return res;
}
int main()
{
int a,b,c,d,k,n;
mobius();
scanf("%d",&n);
while(n--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
int ans=solve(b/k,d/k)+solve((a-1)/k,(c-1)/k)-solve(b/k,(c-1)/k)-solve((a-1)/k,d/k);//容斥
printf("%d\n",ans);
}
return 0;
}
/*
2
2 5 1 5 1
1 5 1 5 2
*/
4.bzoj2005-能量采集:
枚举d.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
bool vis[N];
int mu[N],sum[N];
vector<int>prime;
void mobius()
{
memset(vis,0,sizeof(vis));
memset(mu,0,sizeof(mu));
memset(sum,0,sizeof(sum));
prime.clear();
mu[1]=1;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime.push_back(i);
mu[i]=-1;
}
for(int j=0;j<prime.size()&&i*prime[j]<N;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<N;i++)
sum[i]=sum[i-1]+mu[i];
}
ll solve(int n,int m)
{
int k=min(n,m);
int tn=n,tm=m,tk=k;
ll res=0;
for(int i=1;i<=k;i++)//gcd==i
{
tn=n/i;
tm=m/i;
tk=min(tn,tm);
for(int l=1,r=1;l<=tk;l=r+1)
{
r=min(min(tn/(tn/l),tm/(tm/l)),tk);
res+=((1LL)*(sum[r]-sum[l-1])*(tm/l)*(tn/l))*(1LL)*i;//注意*i,否则,只算了个数。
}
}
return res;
}
int main()
{
int n,m;
while(scanf("%d%d",&n,&m)!=EOF)
{
mobius();
printf("%lld\n",2*solve(n,m)-(1LL)*n*m);//防爆
}
return 0;
}
5.P2257 YY的GCD:
一开始的做法是直接暴力,先筛出 [ 1 , 1 e 7 ] [1,1e7] [1,1e7] 内的所有素数及莫比乌斯函数函数值,然后暴力枚举 m i n ( n , m ) min(n,m) min(n,m) 内的素数,进行数论分块。只过了一半的测试点就 t t t 了。
看了题解后发现还可以继续化简:
A
N
S
=
∑
p
=
1
m
i
n
(
n
,
m
)
i
s
p
r
i
m
e
(
p
)
∗
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
=
p
]
ANS=\sum_{p=1}^{min(n,m)}{isprime(p)}*\sum_{i=1}^{n}{\sum_{j=1}^{m}{[gcd(i,j)==p]}}
ANS=∑p=1min(n,m)isprime(p)∗∑i=1n∑j=1m[gcd(i,j)==p]
=
∑
p
=
1
m
i
n
(
n
,
m
)
i
s
p
r
i
m
e
(
p
)
∗
∑
i
=
1
⌊
n
p
⌋
∑
j
=
1
⌊
m
p
⌋
[
g
c
d
(
i
,
j
)
=
=
1
]
=\sum_{p=1}^{min(n,m)}{isprime(p)*\sum_{i=1}^{\lfloor \frac{n}{p} \rfloor}}{\sum_{j=1}^{\lfloor \frac{m}{p}\rfloor}{[gcd(i,j)==1]}}
=∑p=1min(n,m)isprime(p)∗∑i=1⌊pn⌋∑j=1⌊pm⌋[gcd(i,j)==1](我到这步就直接算了)
=
∑
p
=
1
m
i
n
(
n
,
m
)
i
s
p
r
i
m
e
(
p
)
∗
∑
d
=
1
m
i
n
(
⌊
n
p
⌋
,
⌊
m
p
⌋
)
(
μ
(
d
)
∗
⌊
n
d
∗
p
⌋
∗
⌊
m
d
∗
p
⌋
)
=\sum_{p=1}^{min(n,m)}{isprime(p)*\sum_{d=1}^{min(\lfloor\frac{n}{p}\rfloor,\lfloor\frac{m}{p}\rfloor)}{(\mu(d)*\lfloor\frac{n}{d*p}\rfloor}*\lfloor\frac{m}{d*p}\rfloor)}
=∑p=1min(n,m)isprime(p)∗∑d=1min(⌊pn⌋,⌊pm⌋)(μ(d)∗⌊d∗pn⌋∗⌊d∗pm⌋)
令
T
=
d
∗
p
,
t
=
p
T=d*p,t=p
T=d∗p,t=p
=
∑
t
=
1
m
i
n
(
n
,
m
)
i
s
p
r
i
m
e
(
t
)
∗
∑
t
∣
T
m
i
n
(
n
,
m
)
(
μ
(
t
)
∗
⌊
n
T
⌋
∗
⌊
m
T
⌋
)
=\sum_{t=1}^{min(n,m)}{isprime(t)*\sum_{t|T}^{min(n,m)}{(\mu(t)*\lfloor\frac{n}{T}\rfloor*\lfloor\frac{m}{T}\rfloor)}}
=∑t=1min(n,m)isprime(t)∗∑t∣Tmin(n,m)(μ(t)∗⌊Tn⌋∗⌊Tm⌋)
=
∑
T
=
1
m
i
n
(
n
,
m
)
⌊
n
T
⌋
∗
⌊
m
T
⌋
∗
∑
t
∣
T
,
t
∈
p
r
i
m
e
μ
(
T
t
)
=\sum_{T=1}^{min(n,m)}{\lfloor\frac{n}{T}\rfloor*\lfloor\frac{m}{T}\rfloor*\sum_{t|T,t\in prime}{\mu(\frac{T}{t})}}
=∑T=1min(n,m)⌊Tn⌋∗⌊Tm⌋∗∑t∣T,t∈primeμ(tT)
到此化简结束。
前半部分可以通过数论分块处理,后面可以在求莫比乌斯反演的时候预处理。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
vector<int> prime;
bool vis[N];
int mu[N];
ll sum[N],T[N];
void euler()
{
mu[1]=1;
for(int i=2;i<=N-5;i++)
{
if(!vis[i])
{
prime.push_back(i);
mu[i]=-1;
}
for(int j=0;j<prime.size()&&i*prime[j]<=N-5;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
mu[i*prime[j]]=-mu[i];
}
}
for(int i=0;i<prime.size();i++)
{
for(int j=1;j*prime[i]<=N-5;j++)
T[j*prime[i]]+=mu[j];
}
for(int i=1;i<=N-5;i++)
sum[i]=sum[i-1]+T[i];
}
ll solve(int n,int m)
{
ll res=0;
int minn=min(n,m);
for(int l=1,r=1;l<=minn;l=r+1)
{
r=min(min(m/(m/l),n/(n/l)),minn);//cout<<"r= "<<r<<endl;
res+=1LL*(sum[r]-sum[l-1])*(n/l)*(m/l);
}
return res;
}
int main()
{
int t,n,m;
euler();//cout<<prime.size()<<endl;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
ll ans=solve(n,m);
printf("%lld\n",ans);
}
return 0;
}