题目描述
密码学家正在尝试破解一种叫 BSA 的密码。
他发现,在破解一条消息的同时,他还需要回答这样一种问题:
给出 (a,b,d),求满足 (1 leq x leq a),(1 leq y leq b),且 (gcd(x,y)=d) 的二元组 ((x,y)) 的数量。
因为要解决的问题实在太多了,他便过来寻求你的帮助。
输入格式
输入第一行一个整数 (n),代表要回答的问题个数。
接下来 (n) 行,每行三个整数 (a,b,d)。
输出格式
对于每组询问,输出一个整数代表答案。
(f(x)=sum_{x=1}^asum_{y=1}^b [gcd(x,y)=d])
(f(x)=sum_{x=1}^{a/d}sum_{y=1}^{b/d}[gcd(x,y)=1])
(F(x)=sum_{x|d}^n f(x))=(lfloor{n/x} floor) * (lfloor{m/x} floor)
(f(x)=sum_{x|d}^n u(d/x)*F(d))
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
const int N=5e4+5,M=5e4;
int mu[N],pri[N],tot,n;
bool vis[N];
inline int read(){
int s = 0; char ch = getchar();
while(ch < '0' || ch > '9')ch = getchar();
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s ;
}
signed main(){
n=read();
mu[1]=vis[0]=vis[1]=1;
for(int i=2;i<=M;i++){
if(!vis[i]){ mu[i]=-1; pri[++tot]=i; }
for(int j=1;j<=tot&&pri[j]*i<=M;j++){
vis[pri[j]*i]=1;
if(i%pri[j]==0){ mu[pri[j]*i]=0; break; }
mu[pri[j]*i]=-mu[i];
}
}
for(int i=1;i<=M;i++)mu[i]+=mu[i-1];
int a,b,d;
while(n--){
a=read(),b=read(),d=read();
a/=d; b/=d;
int ans=0,lim=min(a,b);
for(int i=1,j=0;i<=lim;i=j+1){
j=min(a/(a/i),b/(b/i));
ans+=(mu[j]-mu[i-1])*(a/i)*(b/i);
}
printf("%d
",ans);
}
}