题目描述
设 (d(x)) 为 (x) 的约数个数,给定 (n,m),求
(sum_{i=1}^nsum_{j=1}^md(ij))
输入格式
输入文件包含多组测试数据。
第一行,一个整数 (T),表示测试数据的组数。
接下来的 (T) 行,每行两个整数 (n,m)。
输出格式
(T) 行,每行一个整数,表示你所求的答案。
(d(ij)=sum_{x|i}sum_{y|i}[gcd(x,y)=1])
(ANS=sum_{i=1}^nsum_{j=1}^msum_{x|i}sum_{y|i}[gcd(x,y)=1])
(ANS=sum_{x=1}^nsum_{y=1}^m lfloor n/x floor lfloor m/y floor[gcd(x,y)=1])
(ANS=sum_{x=1}^nsum_{y=1}^msum_{d|gcd(x,y)}u(d) lfloor n/x floor lfloor m/y floor)
(令sum(n)=sum_{x=1}^nlfloor n/x floor)
(ANS=sum_{d=1}^nu(d)sum_{x=1}^{n/d}sum_{y=1}^{m/d}lfloor n/x floor lfloor m/y floor)
(ANS=sum_{d=1}^nu(d)*sum(n/d)*sum(m/d))
(O(nsqrt n))预处理sum数组
(O((n+T)sqrt n))总复杂度
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=5e5+10,M=5e4;
#define ll long long
#define int long long
inline int read(){
int x=0; char c=getchar();
while(c<'0'|c>'9')c=getchar();
while('0'<=c&&c<='9'){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); }
return x;
}
inline ll sum(int m){//sqrt
ll ans=0;
for(int i=1,j=0;i<=m;i=j+1){
j=m/(m/i);
ans+=(j-i+1)*(m/i);
}
return ans;
}
ll mu[N],pri[N],f[N],tot;
bool vis[N];
inline void mubius(int n){
mu[1]=vis[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){ pri[++tot]=i; mu[i]=-1; }
for(int j=1;j<=tot&&pri[j]*i<=n;j++){
vis[i*pri[j]]=1;
if(i%pri[j])mu[i*pri[j]]=-mu[i];
else { mu[i*pri[j]]=0; break; }
}
}
for(int i=1;i<=n;i++)mu[i]+=mu[i-1],f[i]=sum(i);
}
signed main(){
int T=read(),n,m;
mubius(5e4);
while(T--){
n=read(),m=read();
ll ans=0;
int lim=min(n,m);
for(int i=1,j=0;i<=lim;i=j+1){//sqrt
j=min(n/(n/i),m/(m/i));
ans+=(mu[j]-mu[i-1])*f[n/i]*f[m/i];
}
printf("%lld
",ans);
}
}