正题
这题出得很明显,直接用莫比乌斯反演求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());//进入函数求解 } }