正题
题目链接:https://www.luogu.com.cn/problem/P4240
题目大意
Q
Q
Q组数据给出
n
,
m
n,m
n,m求
∑
i
=
1
n
∑
j
=
1
m
φ
(
i
×
j
)
\sum_{i=1}^n\sum_{j=1}^m\varphi(i\times j)
i=1∑nj=1∑mφ(i×j)
1
≤
Q
≤
1
0
4
,
1
≤
n
,
m
≤
1
0
5
1\leq Q\leq 10^4,1\leq n,m\leq 10^5
1≤Q≤104,1≤n,m≤105
解题思路
首先需要知道的结论就是
φ
(
i
×
j
)
=
φ
(
i
)
φ
(
j
)
g
c
d
(
i
,
j
)
φ
(
g
c
d
(
i
,
j
)
)
\varphi(i\times j)=\varphi(i)\varphi(j)\frac{gcd(i,j)}{\varphi(gcd(i,j))}
φ(i×j)=φ(i)φ(j)φ(gcd(i,j))gcd(i,j)
然后推一下式子
∑
i
=
1
n
∑
j
=
1
m
φ
(
i
)
φ
(
j
)
g
c
d
(
i
,
j
)
φ
(
g
c
d
(
i
,
j
)
)
\sum_{i=1}^n\sum_{j=1}^m\varphi(i)\varphi(j)\frac{gcd(i,j)}{\varphi(gcd(i,j))}
i=1∑nj=1∑mφ(i)φ(j)φ(gcd(i,j))gcd(i,j)
∑
d
=
1
n
d
φ
(
d
)
∑
d
∣
i
n
∑
d
∣
j
m
φ
(
i
)
φ
(
j
)
[
g
c
d
(
i
,
j
)
=
d
]
\sum_{d=1}^n\frac{d}{\varphi(d)}\sum_{d|i}^n\sum_{d|j}^m\varphi(i)\varphi(j)[gcd(i,j)=d]
d=1∑nφ(d)dd∣i∑nd∣j∑mφ(i)φ(j)[gcd(i,j)=d]
然后莫反一波
∑
d
=
1
n
d
φ
(
d
)
∑
z
∣
d
n
μ
(
z
d
)
∑
z
∣
i
n
∑
z
∣
j
m
φ
(
i
)
φ
(
j
)
\sum_{d=1}^n\frac{d}{\varphi(d)}\sum_{z|d}^n\mu(\frac{z}{d})\sum_{z|i}^n\sum_{z|j}^m\varphi(i)\varphi(j)
d=1∑nφ(d)dz∣d∑nμ(dz)z∣i∑nz∣j∑mφ(i)φ(j)
提出
z
z
z来
∑
z
=
1
n
(
∑
z
∣
i
n
φ
(
i
)
∑
z
∣
j
m
φ
(
j
)
)
∑
d
∣
z
μ
(
z
d
)
d
φ
(
d
)
\sum_{z=1}^n(\sum_{z|i}^n\varphi(i)\sum_{z|j}^m\varphi(j))\sum_{d|z}\mu(\frac{z}{d})\frac{d}{\varphi(d)}
z=1∑n(z∣i∑nφ(i)z∣j∑mφ(j))d∣z∑μ(dz)φ(d)d
后面那个很好求,线性筛然后
O
(
n
log
n
)
O(n\log n)
O(nlogn)处理就好了,并且设为
g
i
g_i
gi,后面需要用到。但是前面那个比较麻烦,而且我们好像就推不动了。
这其实是一个挺经典的 t r a c k track track的,考虑平衡规划。设定一个 T T T,对于小于等于 T T T的部分我们暴力算,对于大于 T T T的部分我们考虑预处理。
设
f
i
,
j
=
∑
j
∣
x
i
φ
(
x
)
f_{i,j}=\sum_{j|x}^i\varphi(x)
fi,j=∑j∣xiφ(x),然后再设一个
h
i
,
j
,
k
h_{i,j,k}
hi,j,k
h
i
,
j
,
k
=
∑
x
=
T
+
1
f
i
,
j
×
f
i
,
k
×
g
i
h_{i,j,k}=\sum_{x=T+1}f_{i,j}\times f_{i,k}\times g_{i}
hi,j,k=x=T+1∑fi,j×fi,k×gi
这个可以用一个前缀和
O
(
n
n
T
2
)
O(n\frac{n}{T}^2)
O(nTn2)的做到。
然后大于 T T T的部分我们就可以用上面预处理的 h h h+整除分块做到 O ( n ) O(\sqrt n) O(n)了。
总共的时间复杂度是
O
(
n
n
+
n
T
2
+
Q
(
T
+
n
)
)
O(n\sqrt n+nT^2+Q(T+\sqrt n))
O(nn+nT2+Q(T+n))
将
T
T
T设为
n
2
3
n^{\frac{2}{3}}
n32就是
O
(
n
n
+
n
4
3
+
Q
n
2
3
)
O(n\sqrt n+n^{\frac{4}{3}}+Qn^{\frac{2}{3}})
O(nn+n34+Qn32)了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#define ll long long
using namespace std;
const ll N=1e5+10,P=998244353;
ll Q,n,m,cnt,pri[N],inv[N],mu[N],phi[N],g[N],o[N];
bool v[N];vector<ll> f[N],h[N];
void prime(){
phi[1]=mu[1]=1;
for(ll i=2;i<N;i++){
if(!v[i])pri[++cnt]=i,phi[i]=i-1,mu[i]=-1;
for(ll j=1;j<=cnt&&i*pri[j]<N;j++){
v[i*pri[j]]=1;
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
mu[i*pri[j]]=-mu[i];
}
}
inv[1]=1;
for(ll i=2;i<N;i++)
inv[i]=P-(P/i)*inv[P%i]%P;
for(ll i=1;i<N;i++)
for(ll j=i;j<N;j+=i)
(g[j]+=inv[phi[i]]*i%P*mu[j/i])%=P;
return;
}
signed main()
{
prime();
ll L=1e5,T=(ll)pow(L,2.0/3.0)+1;
f[0].resize(L+1);
for(ll i=1;i<=L;i++){
f[i].resize(L/i+1);
for(ll j=1;j<=L/i;j++)
f[i][j]=(f[i][j-1]+phi[i*j])%P;
}
h[T].resize((L/T)*(L/T)+1);
for(ll i=T+1;i<=L;i++){
ll p=L/i;h[i].resize(p*p+1);
for(ll j=1;j<=p;j++)
for(ll k=1;k<=p;k++)
h[i][(j-1)*p+k]=(h[i-1][(j-1)*o[i-1]+k]+f[i][j]*f[i][k]%P*g[i]%P)%P;
o[i]=p;
}
scanf("%lld",&Q);
while(Q--){
scanf("%lld%lld",&n,&m);
if(n>m)swap(n,m);ll ans=0;
for(ll i=1;i<=min(T,n);i++)
(ans+=f[i][n/i]*f[i][m/i]%P*g[i]%P)%=P;
for(ll l=T+1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
(ans+=h[r][(n/l-1)*o[r]+m/l]-h[l-1][(n/l-1)*o[l-1]+m/l])%=P;
}
printf("%lld\n",(ans+P)%P);
}
return 0;
}