洛谷题目链接
挺简单的数论题
主要要知道一个式子:$$d(i imes j)=sumlimits_{x|i} sumlimits_{y|j} [gcd(x,y)=1]$$
具体证明其实挺简单的,这里给出一个大佬的博客
那么我们需要求的式子就是:$$sumlimits_{i=1}^N sumlimits_{j=1}^M sumlimits_{x|i} sumlimits_{y|j} [gcd(x,y)=1]$$
分组一下:$$sumlimits_{i=1}^N [x|i] sumlimits_{j=1}^M [y|j] [gcd(x,y)=1]$$
按照套路改为枚举(x,y):$$sumlimits_{x=1}^N leftlfloor frac{N}{x} ight floor sumlimits_{y=1}^M leftlfloor frac{M}{y} ight floor [gcd(x,y)=1]$$
套路的反演也行,不过这里用的是莫比乌斯函数的性质:$$sumlimits_{x=1}^N leftlfloor frac{N}{x} ight floor sumlimits_{y=1}^M leftlfloor frac{M}{y} ight floor sumlimits_{d|gcd(x,y)} mu (d)$$
改为枚举(d)并提前:$$sumlimits_{d=1}^N sumlimits_{x=1}^N sumlimits_{y=1}^M [d|gcd(x,y)] mu (d) leftlfloor frac{N}{x} ight floor leftlfloor frac{M}{y} ight floor$$
分组:$$sumlimits_{d=1}^N mu (d) sumlimits_{x=1}^{leftlfloor frac{N}{d} ight floor} leftlfloor frac{N}{dx} ight floor sumlimits_{y=1}^{leftlfloor frac{M}{d} ight floor} leftlfloor frac{M}{dy} ight floor$$
我们只要求出(sumlimits_{i=1}^n leftlfloor frac{n}{i} ight floor)就行
接下来是美滋滋的代码时间~~~
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 50007
#define int long long
using namespace std;
int T,n,m,cnt;
int mu[N],sum[N],num[N],prime[N];
bool isp[N];
void Get()
{
mu[1]=1;
for(int i=2;i<=N-7;++i)
{
if(!isp[i])
{
prime[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&(i*prime[j])<=N-7;++j)
{
isp[i*prime[j]]=1;
if(i%prime[j]==0)
break;
else
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=N-7;++i)
sum[i]=sum[i-1]+mu[i];
for(int i=1;i<=N-7;++i)
{
int res=0;
for(int l=1,r;l<=i;l=r+1)
{
r=i/(i/l);
res+=(r-l+1)*(i/l);
}
num[i]=res;
}
}
signed main()
{
Get();
scanf("%lld",&T);
while(T--)
{
scanf("%lld%lld",&n,&m);
int ans=0;
if(n>m)
swap(n,m);
for(int l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=(sum[r]-sum[l-1])*num[n/l]*num[m/l];
}
printf("%lld
",ans);
}
return 0;
}