题意
给出n,m,求有多少数对(x,y)满足gcd(x,y)为质数
n,m<=10000000
多组数据T<=10000
分析
设g(d)表示1<=x<=n,1<=y<=m中gcd(x,y)=d的数对数量
设f(d)表示1<=x<=n,1<=y<=m中d|gcd(x,y)的数对数量
显然 f(d)=∑d|ng(n)=⌊nd⌋∗⌊md⌋
反演得 g(d)=∑d|nf(n)μ(nd)
可得 g(1)=∑nd=1μ(nd)⌊nd⌋⌊md⌋
设n<=m
那么 ans=∑np为质数∑nd=1μ(d)⌊npd⌋⌊mpd⌋
设 T=pd
则式子可化简为 ans=∑nT=1⌊nT⌋⌊mT⌋∑p|T且p为质数μ(Tp)
枚举每个质数处理处 ∑p|T且p为质数μ(Tp) 的前缀和然后分块直接上分块大法即可。
记得开long long
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 10000005
#define ll long long
using namespace std;
int n,m,mu[N],s[N],not_prime[N],prime[N],tot;
ll ans;
void getmu(int n)
{
mu[1]=1;
for (int i=2;i<=n;i++)
{
if (!not_prime[i])
{
prime[++tot]=i;
mu[i]=-1;
}
for (int j=1;j<=tot&&i*prime[j]<=n;j++)
{
not_prime[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<=tot;i++)
for (int j=prime[i];j<=n;j+=prime[i])
s[j]+=mu[j/prime[i]];
for (int i=1;i<=n;i++)
s[i]+=s[i-1];
}
void solve()
{
int last;
for (int i=1;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans+=(ll)(n/i)*(m/i)*(s[last]-s[i-1]);
}
}
int main()
{
int T;
scanf("%d",&T);
getmu(10000000);
while (T--)
{
scanf("%d%d",&n,&m);
if (n>m) swap(n,m);
ans=0;
solve();
printf("%lld\n",ans);
}
return 0;
}