正题
这题出得很明显,直接用莫比乌斯反演求gcd(x,y)=d.
你可以设一个函数f(d)表示1~a和1~b中gcd为d的对数。
那么要学会一个套路就是设一个求和函数F(d)表示1~a和1~b中 gcd为d的倍数 的对数。
很明显F(d)=f(d)+f(2d)+f(3d)...
F(d)当然也可以通过一条式子就算出来=(a/d)*(b/d).
接下来的就是看怎么除法分块优化了咯,具体看代码因为我不知道怎么用数学符号表达。。emm
代码<没有分很多函数不要介意>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n;
int d,a,b;
int p[50010];
int miu[50010];
bool tf[50010];
int sum[50010];
long long solve(){
long long ans=0;
int l=1,r;
a/=d;b/=d;//先除一个d,问题就转化为求1到a和1到b中有多少对互质的对数
while(l<=min(a,b)){//l枚举的是当前累加到f(lx)
r=min(a/(a/l),b/(b/l));//除法分块算出右端点,这时候可以知道l~r之间的F(ix)(l<=i<=r)取值都是一样的.
ans=ans+(long long)(a/l)*(b/l)*(sum[r]-sum[l-1]);//所以乘一下这段的miu值和,可以用前缀和算
l=r+1;
}
return ans;
}
int main(){
scanf("%d",&n);
miu[1]=1;
sum[1]=1;
for(int i=2;i<=50000;i++){//线性筛莫比乌斯函数
if(!tf[i]) {miu[i]=-1;p[++p[0]]=i;}
for(int j=1;j<=p[0] && (long long)i*p[j]<=50000;j++){
tf[p[j]*i]=true;
if(i%p[j]==0) {miu[i*p[j]]=0;break;}
miu[i*p[j]]=-miu[i];
}
sum[i]=sum[i-1]+miu[i];//前缀和算出来以便于后面的求解
}
while(n--){
scanf("%d %d %d",&a,&b,&d);
printf("%lld\n",solve());//进入函数求解
}
}