title
Description
设 \(d(x)\) 为 \(x\) 的约数个数,给定 \(N、M\),求 \(\sum^N_{i=1}\sum^M_{j=1}d(ij)\) 。\(1\leqslant N,M,T\leqslant 5\times 10^4\) 。
analysis
首先由一个很神奇的式子开始1:
\[ d(i,j)=\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] \]
因此我们就是在求这个东西了:
\[ \sum^N_{i=1}\sum^M_{j=1}\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] \]
改变求和顺序,先枚举因数 \(x\) 和 \(y\) :
\[ \sum^N_{x=1}\sum^M_{y=1}\lfloor\frac{N}{x}\rfloor\lfloor\frac{M}{y}\rfloor[\gcd(x,y)=1] \]
把 \(x\) 和 \(y\) 换成 \(i\) 和 \(j\) 吧:
\[ \sum^N_{i=1}\sum^M_{j=1}\lfloor\frac{N}{i}\rfloor\lfloor\frac{M}{j}\rfloor[\gcd(i,j)=1] \]
下面开始莫比乌斯反演,设:
\[ f(x)=\sum^N_{i=1}\sum^M_{j=1}\lfloor\frac{N}{i}\rfloor\lfloor\frac{M}{j}\rfloor[\gcd(i,j)=x]\\ g(x)=\sum_{x|d}f(d) \]
则有:
\[ g(x)=\sum^N_{i=1}\sum^M_{j=1}\lfloor\frac{N}{i}\rfloor\lfloor\frac{M}{j}\rfloor[x|\gcd(i,j)] \]
我们把 \(x\) 提出来就可以消除 \(\gcd\) 的影响了:
\[ g(x)=\sum^{\frac{N}{x}}_{i=1}\sum^{\frac{M}{y}}_{j=1}\lfloor\frac{N}{ix}\rfloor\lfloor\frac{M}{jx}\rfloor \]
再根据 \(f(x)\) 的定义,得到答案为 \(f(1)\) ,又因为:
\[ f(n)=\sum_{n|d}\mu(\frac{d}{n})g(d) \]
所以
\[ f(1)=\sum_{1|d}\mu(\frac{d}{1})g(d)=\sum_{i=1}\mu(i)g(i) \]
接下来再考虑如何求 \(g(x)\),我们可以先计算 \(s(x)=\sum\limits_{i=1}^{x} \left\lfloor\frac{x}{i}\right\rfloor\) ,就可以 \(\Theta(1)\) 计算 \(g(x)\) 。
时间复杂度: \(\Theta(T\sqrt{n})\) 。
code
#include<bits/stdc++.h>
typedef long long ll;
const int maxn=5e4;
typedef int iarr[maxn+10];
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
iarr mu,d,cnt,prime;
bool isnotpr[maxn+10];
int tot;
inline void pre()
{
mu[1]=d[1]=1;
for (int i=2; i<=maxn; ++i)
{
if (!isnotpr[i]) prime[++tot]=i, mu[i]=-1, d[i]=2, cnt[i]=1;
for (int j=1; prime[j]*i<=maxn; ++j)
{
isnotpr[prime[j]*i]=1;
if (i%prime[j]==0)
{
mu[prime[j]*i]=0, d[prime[j]*i]=d[i]/(cnt[i]+1)*(cnt[i]+2), cnt[prime[j]*i]=cnt[i]+1;
break;
}
mu[prime[j]*i]=-mu[i], d[prime[j]*i]=d[i]<<1, cnt[prime[j]*i]=1;
}
}
for (int i=1; i<=maxn; ++i) mu[i]+=mu[i-1], d[i]+=d[i-1];
}
int main()
{
pre();
int T;read(T);
while (T--)
{
int n,m;read(n);read(m);
if (n>m) std::swap(n,m);
ll ans=0;
for (int l=1,r; l<=n; l=r+1)
{
r=std::min(n/(n/l),m/(m/l));
ans+=1ll*(mu[r]-mu[l-1])*d[n/l]*d[m/l];
}
write(ans,'\n');
}
IO::flush();
return 0;
}