这题有个奇怪的性质,发现这个性质才可做。
为什么呢?考虑d是p的倍数,i是d的倍数,d可以是p的1~n/p倍,当d=kp时,i可以选n/(pk)个数。
f数组怎么处理呢?O(n√n)就可以吧。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 50010
using namespace std;
long long f[maxn],sum[maxn];
int tot,T;
long long n,m,N;
int prime[maxn],mu[maxn];
bool vis[maxn];
long long cal(long long n,long long m)
{
if (n>m) swap(n,m);
long long last,ans=0;
for (long long i=1;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans+=f[n/i]*f[m/i]*(sum[last]-sum[i-1]);
}
return ans;
}
int main()
{
scanf("%d",&T);
N=50000;
mu[1]=1;
for (int i=2;i<=N;i++)
{
if (!vis[i])
{
prime[++tot]=i;
mu[i]=-1;
}
for (int j=1;j<=tot && i*prime[j]<=N;j++)
{
vis[i*prime[j]]=1;
if (i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for (int i=1;i<=N;i++) sum[i]=sum[i-1]+mu[i];
for (int i=1;i<=N;i++)
{
int last;
for (int j=1;j<=i;j=last+1)
{
last=i/(i/j);
f[i]+=(i/j)*(last-j+1);
}
}
while (T--)
{
scanf("%d%d",&n,&m);
printf("%lld\n",cal(n,m));
}
return 0;
}