BZOJ 3994
Description:
令
D(x)
表示
x
的约数个数。求
Solution:
由对称性,不妨设 $N<=M$
首先我们解决 $D(i*j)$
,
D(i∗j)=∑p|i∑q|j [gcd(ip,q)==1]=∑p|i∑q|j [gcd(p,q)==1]
`
所以
∑Ni=1∑Mj=1D(i∗j)=∑Ni=1∑Mj=1∑p|i∑q|j [gcd(p,q)==1]
=∑Ni=1∑Mj=1[gcd(i,j)==1]∗⌊Ni⌋∗⌊Mj⌋=∑Nd=1μ(d)∑⌊Nd⌋i=1⌊⌊Nd⌋i⌋∑⌊Md⌋j=1⌊⌊Md⌋j⌋
我们可以令 F(x)=∑xi=1⌊xi⌋ ,这些我们可以预处理出来,时间复杂度 O(5000050000−−−−−√)
所以 ∑Ni=1∑Mj=1D(i∗j)=∑Nd=1μ(d)F(⌊Nd⌋)∗F(⌊Md⌋) ,这个我们可以用 O(N−−√) 的时间算出
总的时间复杂度 O(T∗N−−√)
Code:
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int T;
int prime[50010]={0};
int pp=0;
int hash[50010]={0};
int mu[50010]={0};
long long F[50010]={0};
void Pre()
{
mu[1]=1;
for(int i=2;i<=50000;i++)
{
if(hash[i]==0)
{
prime[++pp]=i;
mu[i]=-1;
}
for(int j=1;j<=pp && i*prime[j]<=50000;j++)
{
hash[i*prime[j]]=1;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
mu[i]+=mu[i-1];
}
return;
}
int main()
{
cin>>T;
Pre();
for(int i=1;i<=50000;i++)
{
int last=0;
for(int j=1;j<=i;j=last+1)
{
last=i/(i/j);
F[i]+=(i/j)*(last-j+1);
}
}
for(;T>0;T--)
{
int N,M;
scanf("%d%d",&N,&M);
if(N>M) swap(N,M);
int last=0;
long long ans=0;
for(int i=1;i<=N;i=last+1)
{
last=min(N/(N/i),M/(M/i));
ans+=(mu[last]-mu[i-1])*F[N/i]*F[M/i];
}
printf("%lld\n",ans);
}
return 0;
}