题目链接:Click here
Solution:
首先,我们转化式子
\[
\sum_{i=1}^n\sum_{j=1}^m d(ij)\\
\sum_{i=1}^n\sum_{j=1}^m \sum_{x|i} \sum_{y|j}[gcd(x,y)=1]\\
\]
我们把\(x,y\)给提前
\[
\sum_{x=1}^n\sum_{y=1}^m \lfloor \frac{n}{x} \rfloor \lfloor \frac{m}{y} \rfloor [gcd(x,y)=1]
\]
我们把\(gcd(x,y)\)提前,\(x,y\)不太好看,再给他换个名字\(i,j\)
\[
\sum_{i=1}^n \sum_{j=1}^m \lfloor \frac{n}{i} \rfloor \lfloor \frac{m}{j} \rfloor \sum_{d|i} \sum_{d|j} \mu(d)\\
\]
我们把\(d\)提前
\[
\sum_{d=1}^n \mu(d) \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor} \lfloor \frac{n}{di} \rfloor \lfloor \frac{m}{dj} \rfloor
\]
我们设一个函数\(g(n)=\sum_{i=1}^n \lfloor \frac{n}{i} \rfloor\),则有
\[
\sum_{d=1}^n \mu(d) g(\lfloor \frac{n}{d} \rfloor) g(\lfloor \frac{m}{d} \rfloor)
\]
这个数论分块即可,考虑怎么筛\(g(n)\),我们可以发现\(g(n)=\sum_{i=1}^n d(i)\),则我们筛\(d\)后做前缀和即可
Code:
#include<bits/stdc++.h> #define int long long using namespace std; const int N=5e4+11; int n,m,u[N],p[N],vis[N]; int ans,cnt,g[N],num[N]; int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();} while(isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } void prepare(){ u[1]=1;g[1]=1; for(int i=2;i<N;i++){ if(!vis[i]) p[++cnt]=i,u[i]=-1,g[i]=2,num[i]=1; for(int j=1;j<=cnt&&i*p[j]<N;j++){ vis[i*p[j]]=1; if(i%p[j]==0){ u[i*p[j]]=0; g[i*p[j]]=g[i]/(num[i]+1)*(num[i]+2); num[i*p[j]]=num[i]+1; break; } u[i*p[j]]=-u[i]; g[i*p[j]]=g[i]*2; num[i*p[j]]=1; } } for(int i=1;i<N;i++) u[i]=u[i]+u[i-1],g[i]=g[i]+g[i-1]; } void solve(){ n=read(),m=read(); ans=0; for(int i=1,j;i<=min(n,m);i=j+1){ j=min(n/(n/i),m/(m/i)); ans=ans+(u[j]-u[i-1])*g[n/i]*g[m/i]; } printf("%lld\n",ans); } signed main(){ prepare(); int t=read(); while(t--) solve(); return 0; }