题解:[SDOI2015] 约数个数和
题意分析
不妨令 \(n\leq m\)。
首先,答案为:
\[\sum_{i=1}^n\sum_{j=1}^md(ij)
\]
这个 \(d(ij)\) 表示 \(ij\) 的约数个数,很不好处理。
因此可以考虑 \(d(ij)\) 能否化简,有:
\[d(ij)=\sum_{x\mid i}\sum_{y\mid i}[x\perp y]
\]
证明参见此处。
因此可以进行推导。记答案为 \(\textit{ans}\)
\[\begin{aligned}
\textit{ans}&=\sum_{i=1}^n\sum_{j=1}^m\sum_{x\mid i}\sum_{y\mid i}[x\perp y]\\
&=\sum_{x=1}^n\sum_{y=1}^m[x\perp y]\sum_{i=1}^{\left\lfloor\frac nx\right\rfloor}\sum_{j=1}^{\left\lfloor\frac my\right\rfloor}1\\
&=\sum_{x=1}^n\sum_{y=1}^m[x\perp y]\left\lfloor\frac nx\right\rfloor\left\lfloor\frac my\right\rfloor\\
&=\sum_{x=1}^n\sum_{y=1}^m\sum_{t\mid\gcd(x,y)}\mu(t)\left\lfloor\frac nx\right\rfloor\left\lfloor\frac my\right\rfloor\\
&=\sum_{t=1}^n\mu(t)\sum_{x=1}^{\left\lfloor\frac nt\right\rfloor}\sum_{y=1}^{\left\lfloor\frac mt\right\rfloor}\left\lfloor\frac n{xt}\right\rfloor\left\lfloor\frac m{yt}\right\rfloor\\
&=\sum_{t=1}^n\mu(t)\left(\sum_{x=1}^{\left\lfloor\frac nt\right\rfloor}\left\lfloor\frac n{xt}\right\rfloor\right)\left(\sum_{y=1}^{\left\lfloor\frac mt\right\rfloor}\left\lfloor\frac m{yt}\right\rfloor\right)
\end{aligned}
\]
预处理 \(\displaystyle s_i=\sum_{x=1}^i\left\lfloor\frac ni\right\rfloor\) 即可利用数论分块 \(\mathcal O(\sqrt n)\) 计算。
AC 代码
时间复杂度:\(\mathcal O(T\sqrt n)\)。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=50000;
int mu[N+1];
ll s[N+1];
void pre(){
static int vis[N+1],prime[N+1],size;
mu[1]=1;
for(int i=2;i<=N;i++){
if(!vis[i]){
vis[i]=i;
prime[++size]=i;
mu[i]=-1;
}
for(int j=1;j<=size&&i*prime[j]<=N;j++){
vis[i*prime[j]]=prime[j];
if(i%prime[j]==0){
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=N;i++){
mu[i]+=mu[i-1];
}
for(int i=1;i<=N;i++){
for(int l=1,r;l<=i;l=r+1){
int ti=i/l;
r=i/ti;
s[i]+=(r-l+1ll)*ti;
}
}
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
pre();
int T;
cin>>T;
while(T--){
int n,m;
cin>>n>>m;
if(m>n){
swap(n,m);
}
ll ans=0;
for(int l=1,r;l<=m;l=r+1){
int tn=n/l,tm=m/l;
r=min(n/tn,m/tm);
ans+=(mu[r]-mu[l-1])*s[tn]*s[tm];
}
cout<<ans<<'\n';
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号