求
∑
i
=
1
n
∑
j
=
1
m
d
(
i
j
)
[
d
(
x
)
表
示
x
的
约
数
个
数
]
求\sum_{i=1}^n\sum_{j=1}^m d(ij) [d(x)表示x的约数个数]
求i=1∑nj=1∑md(ij)[d(x)表示x的约数个数]
首
先
,
我
们
要
知
道
如
何
去
求
d
(
i
j
)
,
有
这
么
一
个
式
子
首先,我们要知道如何去求d(ij),有这么一个式子
首先,我们要知道如何去求d(ij),有这么一个式子
d
(
i
j
)
=
∑
x
∣
i
∑
y
∣
j
[
g
c
d
(
i
,
j
)
=
=
1
]
d(ij)=\sum_{x|i}\sum_{y|j}[gcd(i,j)==1]
d(ij)=x∣i∑y∣j∑[gcd(i,j)==1]
于
是
,
我
们
的
式
子
就
变
成
了
要
求
∑
i
=
1
n
∑
j
=
1
m
∑
x
∣
i
∑
y
∣
j
[
g
c
d
(
i
,
j
)
=
=
1
]
于是,我们的式子就变成了要求\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}[gcd(i,j)==1]
于是,我们的式子就变成了要求i=1∑nj=1∑mx∣i∑y∣j∑[gcd(i,j)==1]
改
变
求
和
顺
序
,
先
枚
举
因
数
x
和
y
改变求和顺序,先枚举因数 x 和 y
改变求和顺序,先枚举因数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 \lfloor\frac{n}{x}\rfloor\lfloor\frac{m}{y}\rfloor[gcd(x,y)==1]
于是我们得到了x=1∑ny=1∑m⌊xn⌋⌊ym⌋[gcd(x,y)==1]
到了这一步,我们就可以开始上莫比乌斯反演了
设 f ( x ) = ∑ i = 1 n ∑ j = 1 m ⌊ n i ⌋ ⌊ m j ⌋ [ g c d ( i , j ) = = x ] 设f(x)=\sum_{i=1}^n\sum_{j=1}^m \lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{j}\rfloor[gcd(i,j)==x] 设f(x)=i=1∑nj=1∑m⌊in⌋⌊jm⌋[gcd(i,j)==x]
g
(
n
)
=
∑
n
∣
d
f
(
d
)
g(n)=\sum_{n|d}f(d)
g(n)=n∣d∑f(d)
于
是
g
(
x
)
=
∑
i
=
1
n
∑
j
=
1
m
⌊
n
i
⌋
⌊
m
j
⌋
[
x
∣
g
c
d
(
i
,
j
)
]
于是g(x)=\sum_{i=1}^n\sum_{j=1}^m \lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{j}\rfloor[x|gcd(i,j)]
于是g(x)=i=1∑nj=1∑m⌊in⌋⌊jm⌋[x∣gcd(i,j)]
同 样 我 们 把 x 提 出 来 消 除 g c d , 于 是 我 们 得 到 同样我们把x提出来消除gcd,于是我们得到 同样我们把x提出来消除gcd,于是我们得到
g
(
x
)
=
∑
i
=
1
⌊
n
x
⌋
∑
j
=
1
⌊
m
x
⌋
⌊
n
i
x
⌋
⌊
m
j
x
⌋
g(x)=\sum_{i=1}^{\lfloor\frac{n}{x}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{x}\rfloor} \lfloor\frac{n}{ix}\rfloor\lfloor\frac{m}{jx}\rfloor
g(x)=i=1∑⌊xn⌋j=1∑⌊xm⌋⌊ixn⌋⌊jxm⌋
把
g
(
x
)
带
回
原
来
的
式
子
把g(x)带回原来的式子
把g(x)带回原来的式子
f
(
n
)
=
∑
n
∣
d
g
(
d
)
μ
(
d
n
)
f(n)=\sum_{n|d}g(d)\mu\left(\frac{d}{n}\right)
f(n)=n∣d∑g(d)μ(nd)
f
(
1
)
=
∑
1
∣
d
g
(
d
)
μ
(
d
)
=
∑
d
=
1
m
i
n
(
n
,
m
)
μ
(
d
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
⌊
n
i
d
⌋
⌊
m
j
d
⌋
f(1)=\sum_{1|d}g(d)\mu\left(d\right)=\sum_{d=1}^{min(n,m)}\mu({d})\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} \lfloor\frac{n}{id}\rfloor\lfloor\frac{m}{jd}\rfloor
f(1)=1∣d∑g(d)μ(d)=d=1∑min(n,m)μ(d)i=1∑⌊dn⌋j=1∑⌊dm⌋⌊idn⌋⌊jdm⌋
到
了
这
一
步
之
后
我
们
发
现
,
由
于
⌊
n
i
d
⌋
和
枚
举
y
没
什
么
关
系
,
于
是
又
可
以
把
它
提
前
到了这一步之后我们发现,由于 \lfloor\frac{n}{id}\rfloor和枚举y没什么关系,于是又可以把它提前
到了这一步之后我们发现,由于⌊idn⌋和枚举y没什么关系,于是又可以把它提前
∑
d
=
1
m
i
n
(
n
,
m
)
μ
(
d
)
∑
i
=
1
⌊
n
d
⌋
⌊
n
i
d
⌋
∑
j
=
1
⌊
m
d
⌋
⌊
m
j
d
⌋
\sum_{d=1}^{min(n,m)}\mu({d})\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \lfloor\frac{n}{id}\rfloor\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\lfloor\frac{m}{jd}\rfloor
d=1∑min(n,m)μ(d)i=1∑⌊dn⌋⌊idn⌋j=1∑⌊dm⌋⌊jdm⌋
这
个
复
杂
的
长
的
很
的
式
子
看
得
十
分
难
受
,
于
是
我
们
就
记
这个复杂的长的很的式子看得十分难受,于是我们就记
这个复杂的长的很的式子看得十分难受,于是我们就记
p = ⌊ n i d ⌋ , q = ⌊ m j d ⌋ p=\lfloor\frac{n}{id}\rfloor,q=\lfloor\frac{m}{jd}\rfloor p=⌊idn⌋,q=⌊jdm⌋
于
是
两
个
就
是
很
明
显
的
数
论
分
块
了
,
算
出
来
之
后
再
合
并
起
来
于是两个就是很明显的数论分块了,算出来之后再合并起来
于是两个就是很明显的数论分块了,算出来之后再合并起来
A
n
s
=
∑
d
=
1
m
i
n
(
n
,
m
)
μ
(
d
)
∗
p
∗
q
Ans=\sum_{d=1}^{min(n,m)}\mu({d})*p*q
Ans=d=1∑min(n,m)μ(d)∗p∗q
到这里,就完全推完了,整个的复杂度就是 n ∗ n = n \sqrt{n}*\sqrt{n}=n n∗n=n
于是上一波代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define re register
#define gc getchar()
#define ll long long
inline int read()
{
re int x(0); re char ch(gc);
while(ch>'9'||ch<'0') ch=gc;
while(ch>='0'&&ch<='9') x=(x*10)+(ch^48),ch=gc;
return x;
}
const int N=5e4+10;
int mu[N],pri[N],f[N],vis[N],cnt;
void get_mu(int n) //线性筛求mu函数
{
mu[1]=1;
n-=5;
for(int i=2;i<=n;++i)
{
if(!vis[i])
mu[i]=-1,pri[++cnt]=i;
for(int j=1;j<=cnt&&i*pri[j]<=n;++j)
{
vis[i*pri[j]]=1;
if(i%pri[j]==0)
{
mu[i*pri[j]]=0;
break;
}
else
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=n;++i)
mu[i]+=mu[i-1];
for(int x=1;x<=n;++x)
{
ll res=0;
for(int l=1,r;l<=x;l=r+1)
r=x/(x/l),res+=1LL*(r-l+1)*(x/l);
f[x]=res;
}
}
void work()
{
int a=read(),b=read();
int n=min(a,b);
ll ans=0;
for(int l=1,r;l<=n;l=r+1) //数论分块优化
{
r=min(a/(a/l),b/(b/l));
ans+=1LL*(mu[r]-mu[l-1])*f[a/l]*f[b/l];
}
cout<<ans<<endl;
}
int main()
{
int T=read();
get_mu(N);
while(T--) work();
return 0;
}