链接:P2257 YY的GCD - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意:给定 n,m,求
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
=
p
r
i
m
e
]
\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==prime]
∑i=1n?∑j=1m?[gcd(i,j)==prime]。 题解:
- 首先枚举质数可化为
∑
d
∈
p
r
i
m
e
m
i
n
(
n
,
m
)
∑
i
=
1
n
/
d
∑
j
=
1
m
/
d
[
g
c
d
(
i
,
j
)
=
=
1
]
\sum_{d \in prime }^{min(n,m)}\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}[gcd(i,j)==1]
∑d∈primemin(n,m)?∑i=1n/d?∑j=1m/d?[gcd(i,j)==1]。
- 对于后面的式子先来求其函数的反演,
- 令
f
(
n
,
m
,
d
)
=
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
=
d
]
f(n,m,d)=\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==d]
f(n,m,d)=∑i=1n?∑j=1m?[gcd(i,j)==d],
- 令
F
(
n
,
m
,
d
)
=
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
=
d
?
k
]
,
k
为
任
意
数
F(n,m,d)=\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==d*k],k为任意数
F(n,m,d)=∑i=1n?∑j=1m?[gcd(i,j)==d?k],k为任意数,可以看出 F 为求
g
c
d
(
i
,
j
)
=
=
d
gcd(i,j)==d
gcd(i,j)==d 倍数的个数,那么
F
(
n
,
m
,
d
)
=
?
n
d
?
?
m
d
?
F(n,m,d)=\lfloor \frac{n}{d} \rfloor \lfloor \frac{m}{d} \rfloor
F(n,m,d)=?dn???dm?? 可以
O
(
1
)
O(1)
O(1) 取得。
- 考虑
f
(
a
,
b
,
d
)
f(a,b,d)
f(a,b,d) 与
F
(
a
,
b
,
d
)
F(a,b,d)
F(a,b,d) 的关系。实际上,
F
(
a
,
b
,
d
)
=
∑
d
∣
k
m
i
n
(
a
,
b
)
f
(
a
,
b
,
k
)
F(a,b,d)=\sum_{d|k}^{min(a,b)}f(a,b,k)
F(a,b,d)=∑d∣kmin(a,b)?f(a,b,k),也就是
g
c
d
gcd
gcd 为 d 的倍数的个数都可以取。
- 对 F 进行反演有
f
(
a
,
b
,
n
)
=
∑
n
∣
d
m
i
n
(
a
,
b
)
μ
(
d
n
)
F
(
a
,
b
,
d
)
f(a,b,n)=\sum_{n|d}^{min(a,b)}\mu(\frac{d}{n})F(a,b,d)
f(a,b,n)=∑n∣dmin(a,b)?μ(nd?)F(a,b,d)。(反演公式
f
(
n
)
=
∑
n
∣
d
μ
(
d
n
)
F
(
d
)
f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)
f(n)=∑n∣d?μ(nd?)F(d),不熟的点这里,借用一下别人的博客)
- 回到 1 ,发现
∑
i
=
1
n
/
d
∑
j
=
1
m
/
d
[
g
c
d
(
i
,
j
)
=
=
1
]
\sum_{i=1}^{n/d}\sum_{j=1}^{m/d}[gcd(i,j)==1]
∑i=1n/d?∑j=1m/d?[gcd(i,j)==1] 的值为
f
(
n
d
,
m
d
,
1
)
=
∑
k
=
1
m
i
n
(
n
d
,
m
d
)
μ
(
k
)
F
(
n
d
,
m
d
,
k
)
=
∑
k
=
1
m
i
n
(
n
d
,
m
d
)
μ
(
k
)
?
n
k
?
d
?
?
m
k
?
d
?
f(\frac{n}{d},\frac{m}{d},1)=\sum_{k=1}^{min(\frac{n}{d},\frac{m}{d})}\mu(k)F(\frac{n}{d},\frac{m}{d},k)=\sum_{k=1}^{min(\frac{n}{d},\frac{m}{d})}\mu(k)\lfloor \frac{n}{k*d} \rfloor \lfloor \frac{m}{k*d} \rfloor
f(dn?,dm?,1)=∑k=1min(dn?,dm?)?μ(k)F(dn?,dm?,k)=∑k=1min(dn?,dm?)?μ(k)?k?dn???k?dm?? (代入 4)。
- 答案就是
∑
d
∈
p
r
i
m
e
m
i
n
(
n
,
m
)
∑
k
=
1
m
i
n
(
n
d
,
m
d
)
μ
(
k
)
?
n
k
?
d
?
?
m
k
?
d
?
\sum_{d \in prime }^{min(n,m)}\sum_{k=1}^{min(\frac{n}{d},\frac{m}{d})}\mu(k)\lfloor \frac{n}{k*d} \rfloor \lfloor \frac{m}{k*d} \rfloor
∑d∈primemin(n,m)?∑k=1min(dn?,dm?)?μ(k)?k?dn???k?dm?? 。
- 很明显枚举质数这一位不削掉是不行的,令
T
=
k
?
d
T=k*d
T=k?d,那么原式子化为
∑
d
∈
p
r
i
m
e
m
i
n
(
n
,
m
)
∑
T
=
1
m
i
n
(
n
,
m
)
μ
(
T
d
)
?
n
T
?
?
m
T
?
\sum_{d \in prime }^{min(n,m)}\sum_{T=1}^{min(n,m)}\mu(\frac{T}{d})\lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor
∑d∈primemin(n,m)?∑T=1min(n,m)?μ(dT?)?Tn???Tm??,把第二个累加往外提有
∑
T
=
1
m
i
n
(
n
,
m
)
∑
d
∈
p
r
i
m
e
m
i
n
(
n
,
m
)
μ
(
T
d
)
?
n
T
?
?
m
T
?
\sum_{T=1}^{min(n,m)}\sum_{d \in prime }^{min(n,m)}\mu(\frac{T}{d})\lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor
∑T=1min(n,m)?∑d∈primemin(n,m)?μ(dT?)?Tn???Tm??,发现后面的两个除法与 d 无关,往外提为
∑
T
=
1
m
i
n
(
n
,
m
)
?
n
T
?
?
m
T
?
∑
d
∈
p
r
i
m
e
m
i
n
(
n
,
m
)
μ
(
T
d
)
\sum_{T=1}^{min(n,m)}\lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor\sum_{d \in prime }^{min(n,m)}\mu(\frac{T}{d})
∑T=1min(n,m)??Tn???Tm??∑d∈primemin(n,m)?μ(dT?),观察
∑
d
∈
p
r
i
m
e
m
i
n
(
n
,
m
)
μ
(
T
d
)
\sum_{d \in prime }^{min(n,m)}\mu(\frac{T}{d})
∑d∈primemin(n,m)?μ(dT?),是可以预处理出前缀和的,具体为一个数的该累加值为其质数的倍数的
μ
\mu
μ 值,按质数的倍数去赋值可以做到
n
l
o
g
(
n
)
nlog(n)
nlog(n) 的预处理,然后在求其前缀和 t。
- 答案很明显了,通过整除分块求
?
n
T
?
?
m
T
?
\lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor
?Tn???Tm?? 的同时乘上那一段的前缀和
t
r
?
t
l
?
1
t_{r}-t_{l-1}
tr??tl?1? 。总体复杂度为
O
(
n
l
o
g
(
n
)
+
T
m
i
n
(
n
,
m
)
)
O(nlog(n)+T\sqrt{min(n,m)})
O(nlog(n)+Tmin(n,m)
?) 。需要注意的是整除分块时两个变量的块并不同步,需要取块长较短的那一个作为右端点去求。
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<functional>
#include<queue>
#include<unordered_map>
#include<map>
#include<set>
using namespace std;
using ll=long long;
using P=pair<int,int>;
const ll inf=1e18;
struct MobiusInversion{
static constexpr int maxn=1e7+5;
int cnt;
vector<int>pri,vs,mu,t;
MobiusInversion(int x=maxn):pri(x+5),vs(x+5),mu(x+5),t(x+5){
const int N=x-5;
cnt=0;
vs[0]=vs[1]=1,mu[1]=1;
for(int i=2;i<=N;i++)
{
if(!vs[i])
{
pri[++cnt]=i,mu[i]=-1;
}
for(int j=1;j<=cnt&&i*pri[j]<=N;j++)
{
vs[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=cnt;i++)
{
for(int j=1;pri[i]*j<=N;j++)
{
t[pri[i]*j]+=mu[j];
}
}
for(int i=1;i<=N;i++)t[i]+=t[i-1];
}
ll getans(ll a,ll b){
ll p=min(a,b);
ll ans=0;
for(int l=1,r;l<=p;l=r+1)
{
r=min(a/(a/l),b/(b/l));
ans+=(a/l)*(b/l)*(t[r]-t[l-1]);
}
return ans;
};
}tt;
void solve()
{
ll n,m; cin>>n>>m;
cout<<tt.getans(n,m)<<"\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t; cin>>t;
while(t--)solve();
return 0;
}
|