【BZOJ3994】[SDOI2015]约数个数和 莫比乌斯反演

时间:2023-01-07 23:34:44

【BZOJ3994】[SDOI2015]约数个数和

Description

 设d(x)为x的约数个数,给定N、M,求  【BZOJ3994】[SDOI2015]约数个数和 莫比乌斯反演

Input

输入文件包含多组测试数据。

第一行,一个整数T,表示测试数据的组数。
接下来的T行,每行两个整数N、M。

Output

T行,每行一个整数,表示你所求的答案。

Sample Input

2
7 4
5 6

Sample Output

110
121

HINT

1<=N, M<=50000

1<=T<=50000

题解:依旧是这个结论

【BZOJ3994】[SDOI2015]约数个数和 莫比乌斯反演

但由于这次是多组询问,我们先O(nsqrt(n))预处理【BZOJ3994】[SDOI2015]约数个数和 莫比乌斯反演,然后就能O(sqrt(n))回答询问了。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int m=50000;
int sm[m+10],mu[m+10],pri[m+10];
bool np[m+10];
int T,num;
ll x,y;
ll f[m+10];
int main()
{
ll i,j,last,ans,x,y;
sm[1]=mu[1]=1;
for(i=2;i<=m;i++)
{
if(!np[i]) pri[++num]=i,mu[i]=-1;
sm[i]=sm[i-1]+mu[i];
for(j=1;j<=num&&i*pri[j]<=m;j++)
{
np[i*pri[j]]=1;
if(i%pri[j]==0)
{
mu[i*pri[j]]=0;
break;
}
mu[i*pri[j]]=-mu[i];
}
}
for(i=1;i<=m;i++) for(j=1;j<=i;j=last+1) last=i/(i/j),f[i]+=(last-j+1)*(i/j);
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld",&x,&y),ans=0;
if(x<y) swap(x,y);
for(i=1;i<=y;i=last+1)
{
last=min(x/(x/i),y/(y/i));
ans+=(sm[last]-sm[i-1])*f[x/i]*f[y/i];
}
printf("%lld\n",ans);
}
return 0;
}