困扰了我半年的莫比乌斯,今天终于有了进展。本人是数论小白,数学基础不好,对数学不敏感,对数学公式推导转化头疼,所以才学的慢,下面我以一个数学不好的人的视角学习。
为了解决哪些问题?
∑ ∑ f ( x ) \sum\sum f(x) ∑∑f(x)这样的式子,比如 ∑ i = 1 n ∑ j = 1 n g c d ( i , j ) \sum_{i=1}^n\sum_{j=1}^ngcd(i,j) ∑i=1n∑j=1ngcd(i,j)之类的
莫比乌斯函数
u ( n ) = { 1 n = 1 ( − 1 ) k n 无 平 方 数 因 子 , k 为 不 同 因 子 个 数 0 n 有 大 于 1 的 平 方 数 因 子 u(n) = \begin{cases} 1 & n = 1 \\ (-1)^k & n无平方数因子,k为不同因子个数 \\ 0& n有大于1的平方数因子 \end{cases} u(n)=⎩⎪⎨⎪⎧1(−1)k0n=1n无平方数因子,k为不同因子个数n有大于1的平方数因子
重要的性质
∑ d ∣ n u ( d ) = [ n = 1 ] \sum_{d|n}u(d)=[n=1] d∣n∑u(d)=[n=1]
莫比乌斯函数的线性筛
类似线性筛素数,线性筛出莫比乌斯函数的值及其前缀和。
const int N=1e6+10,M=1e6;
int cnt,vis[N],prime[N],Smu[N],mu[N];
void init_mu() { //线性筛莫比乌斯函数
Smu[1]=mu[1]=1;
cnt=0;
for(int i=2; i<=M; i++) {
if(vis[i]==0) {
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1; j<=cnt; j++) {
if(i*prime[j]>M)break;
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=2;i<=M;i++)Smu[i]=Smu[i-1]+mu[i];
}
如何使用?
套路1
[
g
c
d
(
i
,
j
)
=
1
]
=
∑
d
∣
g
c
d
(
i
,
j
)
u
(
d
)
[gcd(i,j)=1]=\sum_{d|gcd(i,j)}u(d)
[gcd(i,j)=1]=d∣gcd(i,j)∑u(d)
[
g
c
d
(
a
1
,
a
2
,
a
3
…
…
a
n
)
=
1
]
=
∑
d
∣
g
c
d
(
a
1
,
a
2
,
a
3
…
…
a
n
)
u
(
d
)
[gcd(a_1,a_2,a_3……a_n)=1]=\sum_{d|gcd(a_1,a_2,a_3……a_n)}u(d)
[gcd(a1,a2,a3……an)=1]=d∣gcd(a1,a2,a3……an)∑u(d)
套路2:枚举d,这样就不用判断 d|gcd(i,j) ,就可以将其消去
∑
i
=
1
n
∑
j
=
1
m
∑
d
∣
g
c
d
(
i
,
j
)
1
=
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
d
]
=
∑
i
=
1
n
/
d
∑
j
=
1
m
/
d
=
[
n
d
]
[
m
d
]
\sum_{i=1}^n\sum_{j=1}^m \sum_{d|gcd(i,j)}1=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]=\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}=[\frac{n}{d}][\frac{m}{d}]
i=1∑nj=1∑md∣gcd(i,j)∑1=i=1∑nj=1∑m[gcd(i,j)=d]=i=1∑n/dj=1∑m/d=[dn][dm]
即求满足:gcd(i,j)等于d或d的倍数的对数。
证明:d|i 的 i 有
[
n
d
]
[\frac{n}{d}]
[dn]个,d|j 的 j 有
[
m
d
]
[\frac{m}{d}]
[dm]个。这些 i,j 两两组合的gcd均为d或d的倍数。
例题1.1
∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = 1 ] ( n < m ) \sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=1] (n<m) i=1∑nj=1∑m[gcd(i,j)=1](n<m)
1.由套路1变形得到
∑
i
=
1
n
∑
j
=
1
m
∑
d
∣
g
c
d
(
i
,
j
)
u
(
d
)
\sum_{i=1}^n\sum_{j=1}^m\sum_{d|gcd(i,j)}u(d)
i=1∑nj=1∑md∣gcd(i,j)∑u(d)
2.由套路2变形得到
∑
d
=
1
n
u
(
d
)
∗
[
n
d
]
[
m
d
]
\sum_{d=1}^nu(d)*[\frac{n}{d}][\frac{m}{d}]
d=1∑nu(d)∗[dn][dm]
3.u(d)的前缀和筛出来,最后整除分块即可
由于线性筛是O(n)的,所以单次查询情况下,时间复杂度并没有降下来,但在多次查询的情况下,是快了很多的。
代码如下
long long solve(long long n,long long m) {
if(n==0||m==0)return 0;
if(n>m)swap(n,m);
long long ans=0;
for(int l=1,r; l<=n; l=r+1) { //整除分块
r=min(n/(n/l),m/(m/l));
ans+=(Smu[r]-Smu[l-1])*(n/l)*(m/l);
}
return ans;
}
例题1.2
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
k
]
(
n
<
m
)
\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=k] (n<m)
i=1∑nj=1∑m[gcd(i,j)=k](n<m)
变形得到
∑
i
=
1
n
/
k
∑
j
=
1
m
/
k
[
g
c
d
(
i
,
j
)
=
1
]
\sum_{i=1}^{n/k}\sum_{j=1}^{m/k}[gcd(i,j)=1]
i=1∑n/kj=1∑m/k[gcd(i,j)=1]
就是例题1.1了。
long long solve(long long n,long long m,long long k) {
n/=k,m/=k;
if(n==0||m==0)return 0;
if(n>m)swap(n,m);
long long ans=0;
for(int l=1,r; l<=n; l=r+1) { //整除分块
r=min(n/(n/l),m/(m/l));
ans+=(Smu[r]-Smu[l-1])*(n/l)*(m/l);
}
return ans;
}
例题1.3
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
p
r
i
m
e
]
(
n
<
m
)
\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=prime] (n<m)
i=1∑nj=1∑m[gcd(i,j)=prime](n<m)
1.枚举 p,变形得到
∑
p
∈
p
r
i
m
e
∑
i
=
1
n
/
p
∑
j
=
1
m
/
p
[
g
c
d
(
i
,
j
)
=
1
]
\sum_{p\in prime}\sum_{i=1}^{n/p}\sum_{j=1}^{m/p}[gcd(i,j)=1]
p∈prime∑i=1∑n/pj=1∑m/p[gcd(i,j)=1]
2.后面这个式子就是例题1嘛,变=>
∑
p
∈
p
r
i
m
e
∑
d
=
1
n
/
p
u
(
d
)
∗
[
n
p
d
]
∗
[
m
p
d
]
\sum_{p\in prime}\sum_{d=1}^{n/p}u(d)*[\frac{n}{pd}]*[\frac{m}{pd}]
p∈prime∑d=1∑n/pu(d)∗[pdn]∗[pdm]
3.令k=pd,变=>
∑
p
∈
p
r
i
m
e
∑
d
=
1
n
/
p
u
(
k
p
)
∗
[
n
k
]
∗
[
m
k
]
\sum_{p\in prime}\sum_{d=1}^{n/p}u(\frac{k}{p})*[\frac{n}{k}]*[\frac{m}{k}]
p∈prime∑d=1∑n/pu(pk)∗[kn]∗[km]
4.枚举k,变=>
∑
k
=
1
n
∑
p
∈
p
r
i
m
e
,
p
∣
k
u
(
k
p
)
∗
[
n
k
]
∗
[
m
k
]
\sum_{k=1}^n\sum_{p\in prime,p|k}u(\frac{k}{p})*[\frac{n}{k}]*[\frac{m}{k}]
k=1∑np∈prime,p∣k∑u(pk)∗[kn]∗[km]
5.令
f
(
x
)
=
∑
p
∈
p
r
i
m
e
,
p
∣
x
u
(
x
p
)
f(x)=\sum_{p \in prime,p|x}u(\frac{x}{p})
f(x)=∑p∈prime,p∣xu(px),变=>
∑
k
=
1
n
f
(
k
)
∗
[
n
k
]
∗
[
m
k
]
\sum_{k=1}^nf(k)*[\frac{n}{k}]*[\frac{m}{k}]
k=1∑nf(k)∗[kn]∗[km]
6.由整除分块可知,若可以求出f(x)函数的前缀和,就可以轻而易举的求出这个式子了。怎么求???(等等,之后再写)
例题1.4
∑ i = 1 n ∑ j = 1 n g c d ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^ngcd(i,j) i=1∑nj=1∑ngcd(i,j)
1.枚举 x,gcd(i,j)=x
∑
x
=
1
n
x
×
∑
i
=
1
n
∑
j
=
1
n
[
g
c
d
(
i
,
j
)
=
x
]
\sum_{x=1}^nx\times\sum_{i=1}^{n}\sum_{j=1}^n[gcd(i,j)=x]
x=1∑nx×i=1∑nj=1∑n[gcd(i,j)=x]
=
∑
x
=
1
n
x
×
∑
i
=
1
n
/
x
∑
j
=
1
n
/
x
[
g
c
d
(
i
,
j
)
=
1
]
=\sum_{x=1}^nx\times\sum_{i=1}^{n/x}\sum_{j=1}^{n/x}[gcd(i,j)=1]
=x=1∑nx×i=1∑n/xj=1∑n/x[gcd(i,j)=1]
2.根据套路1变形
=
∑
x
=
1
n
x
×
∑
i
=
1
n
/
x
∑
j
=
1
n
/
x
∑
d
∣
g
c
d
(
i
,
j
)
u
(
d
)
=\sum_{x=1}^nx\times\sum_{i=1}^{n/x}\sum_{j=1}^{n/x}\sum_{d|gcd(i,j)}u(d)
=x=1∑nx×i=1∑n/xj=1∑n/xd∣gcd(i,j)∑u(d)
3.再根据套路2,枚举d
=
∑
x
=
1
n
x
×
∑
d
=
1
n
/
x
[
n
d
x
]
[
n
d
x
]
u
(
d
)
=\sum_{x=1}^nx\times\sum_{d=1}^{n/x}[\frac{n}{dx}][\frac{n}{dx}]u(d)
=x=1∑nx×d=1∑n/x[dxn][dxn]u(d)
令
f
(
i
)
=
∑
d
=
1
i
[
i
d
]
[
i
d
]
u
(
d
)
f(i)=\sum_{d=1}^i[\frac{i}{d}][\frac{i}{d}]u(d)
f(i)=∑d=1i[di][di]u(d),这个式子整除分块
O
(
n
1
/
2
)
O(n^{1/2})
O(n1/2) 求
原
式
=
∑
x
=
1
n
x
×
f
(
[
n
x
]
)
原式=\sum_{x=1}^nx\times f([\frac{n}{x}])
原式=x=1∑nx×f([xn])
这个式子也整除分块
O
(
n
1
/
2
)
O(n^{1/2})
O(n1/2) 求
总时间复杂度: O ( n ) O(n) O(n)
long long f(long long n) {
long long ans=0;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=1ll*(n/l)*(n/l)*(Smu[r]-Smu[l-1]);
}
return ans;
}
int main() {
init_mu();
long long n,ans=0;
cin>>n;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=1ll*(r-l+1)*(l+r)/2*f(n/l);
}
cout<<ans;
}
例题2.1
∑
i
=
1
n
∑
j
=
1
m
f
(
i
j
)
,
n
<
=
m
\sum_{i=1}^n \sum_{j=1}^m f(ij),n<=m
i=1∑nj=1∑mf(ij),n<=m
【注意】其中
f
(
x
)
f(x)
f(x) 表示 x 的因子个数。
1.将 d(i,j) 展开
f
(
i
j
)
=
∑
x
∣
i
∑
y
∣
j
[
g
c
d
(
x
,
y
)
=
1
]
f(ij)=\sum_{x|i}\sum_{y|j} [gcd(x,y)=1]
f(ij)=x∣i∑y∣j∑[gcd(x,y)=1]
2.原式转化,变=>
∑
i
=
1
n
∑
j
=
1
m
∑
x
∣
i
∑
y
∣
j
[
g
c
d
(
x
,
y
)
=
1
]
\sum_{i=1}^n \sum_{j=1}^m \sum_{x|i}\sum_{y|j} [gcd(x,y)=1]
i=1∑nj=1∑mx∣i∑y∣j∑[gcd(x,y)=1]
3.更换枚举项,枚举x,y,变=>
∑
x
=
1
n
∑
y
=
1
m
[
n
x
]
[
m
y
]
[
g
c
d
(
x
,
y
)
=
1
]
\sum_{x=1}^n\sum_{y=1}^m [\frac{n}{x}][\frac{m}{y}][gcd(x,y)=1]
x=1∑ny=1∑m[xn][ym][gcd(x,y)=1]
=
∑
i
=
1
n
∑
j
=
1
m
[
n
i
]
[
m
j
]
[
g
c
d
(
i
,
j
)
=
1
]
=\sum_{i=1}^n\sum_{j=1}^m [\frac{n}{i}][\frac{m}{j}][gcd(i,j)=1]
=i=1∑nj=1∑m[in][jm][gcd(i,j)=1]
4.套路1变形,变=>
∑
i
=
1
n
∑
j
=
1
m
[
n
i
]
[
m
j
]
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
\sum_{i=1}^n\sum_{j=1}^m [\frac{n}{i}][\frac{m}{j}]\sum_{d|gcd(i,j)}\mu(d)
i=1∑nj=1∑m[in][jm]d∣gcd(i,j)∑μ(d)
5.与套路2的思路一致,枚举d,这样就不用考虑 d|gcd(i,j),变=>
∑
d
=
1
n
∑
x
=
1
n
/
d
∑
y
=
1
m
/
d
[
n
d
x
]
[
m
d
y
]
μ
(
d
)
\sum_{d=1}^{n} \sum_{x=1}^{n/d}\sum_{y=1}^{m/d}[\frac{n}{dx}][\frac{m}{dy}]\mu(d)
d=1∑nx=1∑n/dy=1∑m/d[dxn][dym]μ(d)
=
∑
d
=
1
n
μ
(
d
)
∑
x
=
1
n
/
d
[
n
d
x
]
∑
y
=
1
m
/
d
[
m
d
y
]
=\sum_{d=1}^{n}\mu(d)\sum_{x=1}^{n/d}[\frac{\frac{n}{d}}{x}]\sum_{y=1}^{m/d}[\frac{\frac{m}{d}}{y}]
=d=1∑nμ(d)x=1∑n/d[xdn]y=1∑m/d[ydm]
6.整除分块
优化:后面两坨的形式一样,可以使用整除分块预处理出函数
g
(
x
)
=
∑
i
=
1
x
[
x
i
]
g(x)=\sum_{i=1}^x [\frac{x}{i}]
g(x)=∑i=1x[ix]的所有值,预处理时间复杂度
O
(
n
3
/
2
)
O(n^{3/2})
O(n3/2)。然后每次O(n)求,时间复杂度
O
(
T
n
+
n
3
/
2
)
O(Tn+n^{3/2})
O(Tn+n3/2)。
继续优化:预处理完第一步之后,求得式子就是
∑
d
=
1
n
u
(
d
)
×
g
(
n
/
d
)
×
g
(
m
/
d
)
\sum_{d=1}^n u(d)\times g(n/d)\times g(m/d)
∑d=1nu(d)×g(n/d)×g(m/d) ,这步还可以再整除分块。时间复杂度
O
(
T
n
1
/
2
+
n
3
/
2
)
O(Tn^{1/2}+n^{3/2})
O(Tn1/2+n3/2)。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=5e4;
long long mu[N],prime[N],cnt,vis[N],Smu[N],g[N];
void init_Smu() {
Smu[1]=mu[1]=1;
for(int i=2; i<=M; i++) {
if(vis[i]==0) {
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1; j<=cnt; j++) {
if(i*prime[j]>M)break;
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=2; i<=M; i++)Smu[i]=Smu[i-1]+mu[i];
for(int i=1; i<=M; i++) {
for(int l=1,r=2; l<=i; l=r+1) {
r=i/(i/l);
g[i]+=(r-l+1)*(i/l);
}
}
}
int main() {
long long T,n,m;
cin>>T;
init_Smu();
while(T--) {
cin>>n>>m;
if(n>m)swap(n,m);
long long ans=0;
for(int l=1,r=2;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(Smu[r]-Smu[l-1])*g[n/l]*g[m/l];
}
cout<<ans<<endl;
}
return 0;
}
例题2.2
题目描述: T组询问,一张 n×m 的数表,其中 aij 为能同时整除 i 和 j 的所有自然数之和。给定 b,计算数表中不大于 b 的数之和。T,n<=1e5。
问题分析:
∑
i
=
1
n
∑
j
=
1
m
f
(
g
c
d
(
i
,
j
)
)
[
f
(
g
c
d
(
i
,
j
)
)
<
=
b
]
,
n
<
=
m
\sum_{i=1}^{n}\sum_{j=1}^{m}f(gcd(i,j))[f(gcd(i,j))<=b],n<=m
i=1∑nj=1∑mf(gcd(i,j))[f(gcd(i,j))<=b],n<=m
【注意】其中
f
(
x
)
f(x)
f(x) 表示 x 的因子的和。
1.先不考虑后面那个限制,枚举
g
c
d
(
i
,
j
)
=
x
gcd(i,j) = x
gcd(i,j)=x ,并用套路1变形
∑
x
=
1
n
∑
i
=
1
n
∑
j
=
1
m
f
(
x
)
[
g
c
d
(
i
,
j
)
=
x
]
\sum_{x=1}^n\sum_{i=1}^{n}\sum_{j=1}^{m}f(x)[gcd(i,j)=x]
x=1∑ni=1∑nj=1∑mf(x)[gcd(i,j)=x]
=
∑
x
=
1
n
∑
i
=
1
n
/
x
∑
j
=
1
m
/
x
f
(
x
)
[
g
c
d
(
i
,
j
)
=
1
]
\sum_{x=1}^n\sum_{i=1}^{n/x}\sum_{j=1}^{m/x}f(x)[gcd(i,j)=1]
x=1∑ni=1∑n/xj=1∑m/xf(x)[gcd(i,j)=1]
=
∑
x
=
1
n
f
(
x
)
∑
i
=
1
n
/
x
∑
j
=
1
m
/
x
∑
d
∣
g
c
d
(
i
,
j
)
u
(
d
)
=\sum_{x=1}^nf(x)\sum_{i=1}^{n/x}\sum_{j=1}^{m/x}\sum_{d|gcd(i,j)}u(d)
=x=1∑nf(x)i=1∑n/xj=1∑m/xd∣gcd(i,j)∑u(d)
2.根据套路2,枚举 d 变形
∑
x
=
1
n
f
(
x
)
∑
d
=
1
n
/
x
[
n
d
x
]
[
m
d
x
]
u
(
d
)
\sum_{x=1}^nf(x)\sum_{d=1}^{n/x}[\frac{n}{dx}][\frac{m}{dx}]u(d)
x=1∑nf(x)d=1∑n/x[dxn][dxm]u(d)
3.观察后面那个式子,令
g
(
i
)
=
∑
d
=
1
i
[
i
d
]
[
m
/
x
d
]
u
(
d
)
g(i)=\sum_{d=1}^i[\frac{i}{d}][\frac{m/x}{d}]u(d)
g(i)=∑d=1i[di][dm/x]u(d) 是可以整除分块O(sqrt(n))求出来的
∑
x
=
1
n
f
(
x
)
g
(
[
n
x
]
)
\sum_{x=1}^nf(x)g([\frac{n}{x}])
x=1∑nf(x)g([xn])
4.发现又可以整除分块。
方法1:O(n) 求出 f(x) 的时候,把 f(x)>b 的项当成0 ,并计算前缀和。TLE
方法2:对查询的 b 升序排序,用树状数组维护前缀和,最初 f(x) 为 0,随便 b 的增大,单点修改
【错误】
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=1e5+5;
const long long mod=(1ll<<31);
struct quest {
long long n,m,b,id;
} q[N];
struct node {
long long v,id;
} f[N];
int cmp1(node x,node y) {
return x.v<y.v;
}
int cmp(quest x,quest y) {
return x.b<y.b;
}
long long ans[N],c[N];
long long cnt,vis[N],prime[N],Smu[N],mu[N];
void init_Smu() { //线性筛莫比乌斯函数
Smu[1]=mu[1]=1;
for(int i=2; i<=M; i++) {
if(vis[i]==0) {
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1; j<=cnt; j++) {
if(i*prime[j]>M)break;
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
else mu[i*prime[j]]=-mu[i];
}
}
for(int i=2; i<=M; i++)Smu[i]=Smu[i-1]+mu[i];
}
void init_S() {
for(int i=1; i<=M; i++) {
for(int j=i; j<=M; j+=i) {
f[j].v+=i;
}
f[i].id=i;
}
sort(f+1,f+M+1,cmp1);
}
int lowbit(int x) {
return x&(-x);
}
void update(long long k,long long x) {
for(int i=k; i<=M; i+=lowbit(i))c[i]+=x;
}
long long query(long long l,long long r) {
long long ans=0;
for(int i=r; i>0; i-=lowbit(i))ans+=c[i];
for(int i=l-1; i>0; i-=lowbit(i))ans-=c[i];
return ans;
}
long long g(long long n,long long m) {
long long ans=0;
for(int l=1,r; l<=n; l=r+1) {
r=min(n/(n/l),m/(m/l));
ans+=(Smu[r]-Smu[l-1])*(n/l)*(m/l);
ans=ans%mod;
}
return ans;
}
int main() {
freopen("1538.txt","r",stdin);
init_S();
init_Smu();
long long T;
cin>>T;
for(int i=1; i<=T; i++) {
scanf("%lld%lld%lld",&q[i].n,&q[i].m,&q[i].b);
if(q[i].n>q[i].m)swap(q[i].n,q[i].m);
q[i].id=i;
}
sort(q+1,q+T,cmp);
int now=0;
for(int i=1; i<=T; i++) {
while(f[now+1].v<=q[i].b&&now<M) {
now++;
update(f[now].id,f[now].v);
}
long long ret=0;
for(int l=1,r; l<=q[i].n; l=r+1) {
r=q[i].n/(q[i].n/l);
ret+=query(l,r)*g(q[i].n/l,q[i].m/l);
ret=ret%mod;
}
ans[q[i].id]=ret;
}
for(int i=1; i<=T; i++)printf("%lld\n",ans[i]);
return 0;
}
例题3
∑ i = a b ∑ j = c d [ g c d ( i , j ) = k ] \sum_{i=a}^b\sum_{j=c}^d [gcd(i,j)=k] i=a∑bj=c∑d[gcd(i,j)=k]
1.容斥一下就是例题1.2了
a n s = ∑ i = 1 b ∑ j = 1 d [ g c d ( i , j ) = k ] − ∑ i = 1 a − 1 ∑ j = 1 d [ g c d ( i , j ) = k ] − ∑ i = 1 b ∑ j = 1 c − 1 [ g c d ( i , j ) = = k ] + ∑ i = 1 a − 1 ∑ j = 1 c − 1 [ g c d ( i , j ) = k ] ans=\sum_{i=1}^b\sum_{j=1}^d [gcd(i,j)=k]-\sum_{i=1}^{a-1}\sum_{j=1}^d [gcd(i,j)=k]-\sum_{i=1}^b\sum_{j=1}^{c-1}[gcd(i,j)==k]+\sum_{i=1}^{a-1}\sum_{j=1}^{c-1}[gcd(i,j)=k] ans=i=1∑bj=1∑d[gcd(i,j)=k]−i=1∑a−1j=1∑d[gcd(i,j)=k]−i=1∑bj=1∑c−1[gcd(i,j)==k]+i=1∑a−1j=1∑c−1[gcd(i,j)=k]