博主又来水文章了,这是做的第一道莫比乌斯函数的题目
思路
题目让我们求\(x\leq a,y\leq b\)有多少对\((x,y)\)满足\(\gcd(x,y)=d\)
等价于求
有多少对\((x,y)\)满足\(x\leq x/d,y \leq b/d\),使得\(\gcd(x,y)=1\)
设\(d(a,b,k)\)表示有多少对\((x,y)\)满足\(x\leq a,y \leq b\)且\(k|gcd(a,b)\)
\[d(a,b,k)=\left\lfloor\dfrac{a}{k}\right\rfloor*\left\lfloor\dfrac{b}{k}\right\rfloor \]
这式子是能用整除分块优化
设\(f(a,b)\)表示有多少对\((x,y)\)满足\(x\leq a,y \leq b\)且\(gcd(x,y)=1\)
根据容斥原理得
\[f(a,b)=\mu(i)*d(a,b,i) \]
这里意思大概就是没有任何限制的二元组数量为\(d(a,b,1)\),然后减去\(gcd(x,y)\)是\(2,3,5……\)的倍数的二元组数量,然后加回来\(gcd(x,y)\)既是\(2\)又是\(3\)的倍数的……
\(code\)
/*
@ author:pyyyyyy
-----思路------
-----debug-------
memset(miu,1,sizeof(miu))不是把miu全赋值成1,我傻了
*/
#include<bits/stdc++.h>
using namespace std;
const int N=50041;
int T,a,b,d;
int miu[N],v[N];
void prime(int n)
{
for(int i=2;i<=n;++i)
{
if(v[i]) continue;
miu[i]=-1;
for(int j=2*i;j<=n;j+=i)
{
v[j]=1;
if((j/i)%i==0) miu[j]=0;
else miu[j]*=-1;
}
}
}
int Zap(){
a/=d,b/=d;
int ans=0;
if(a>b) swap(a,b);
for(int l=1,r;l<=a;l=r+1)
{
r=min(a/(a/l),b/(b/l));
ans+=(miu[r]-miu[l-1])*(a/l)*(b/l);
}
return ans;
}
int main()
{
for(int i=1;i<N;++i) miu[i]=1;
prime(N);
for(int i=1;i<N;++i) miu[i]+=miu[i-1];
cin>>T;
while(T--)
{
cin>>a>>b>>d;
cout<<Zap()<<'\n';
}
return 0;
}