传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1101
思路:设a<b
求的就是f(a,b,d)=ΣΣ[gcd(i,j)==d](1<=i<=a,1<=j<=b)
又有公式Σmiu(d) =[n==1] (d|n) //miu是莫比乌斯函数
把n用gcd(i,j)代入得
ΣΣΣmiu(d)(d|gcd(i,j),1<=i<=a,1<=j<=b)
=Σmiu(d)*(a/d)*(b/d)分段统计即可
分成a/d和b/d都相同的2*sqrt(n)段,乘上这一段的miu的和即可O(sqrt(n))回答了
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=50010;
int mu[maxn],A,B,d,pri[maxn],tot,ans,cas,smu[maxn];bool isp[maxn];
void prework(){
memset(isp,1,sizeof(isp));
isp[1]=0,mu[1]=1;
for (int i=2;i<=maxn-10;i++){
if (isp[i]) mu[i]=-1,pri[++tot]=i;
for (int j=1;j<=tot&&i*pri[j]<=maxn-10;j++){
isp[i*pri[j]]=0;
if (!(i%pri[j])){mu[i*pri[j]]=0;break;}
mu[i*pri[j]]=mu[i]*-1;
}
}
for (int i=1;i<=maxn-10;i++) smu[i]=smu[i-1]+mu[i];
//for (ll i=1;i<=50;i++) printf("%lld %d\n",i,isp[i]);
}
int getans(int a,int b){
int ans=0,ed=0;
for (int st=1;st<=B;st=ed+1){
ed=min(a/(a/st),b/(b/st));
ans+=(smu[ed]-smu[st-1])*(a/st)*(b/st);
}
return ans;
}
int main(){
prework();
scanf("%d",&cas);
while (cas--){
ans=0;
scanf("%d%d%d",&A,&B,&d);
if (A<B) swap(A,B);A/=d,B/=d;
printf("%d\n",getans(A,B));
}
return 0;
}