Zap
【题目描述】
FGD正在破解一段密码,他需要回答很多类似的问题:
对于给定的整数
a
,
作为FGD的同学,FGD希望得到你的帮助。
【输入描述】
第一行包含一个正整数
n
,表示一共有
接下来
n
行,每行表示一个询问,每行三个正整数,分别为
【输出描述】
对于每组询问,输出一个正整数,表示满足条件的整数对数。
【样例输入】
2
4 5 2
6 4 3
【样例输出】
3
2
【Solution】
求 gcd(x,y)=k , x<=a,y<=b 的对数,等价于求 gcd(x,y)=1 , x<=⌊ak⌋,y<=⌊bk⌋ 的对数。
∴ans=∑i=1nμ(i)⋅⌊⌊ak⌋i⌋⋅⌊⌊bk⌋i⌋
维护一下 μ 函数的前缀和,然后就可以分块优化了。
【Code】
#include <iostream>
#include <cstdio>
#define LL long long
#define Min(x,y) ((x)<(y)?(x):(y))
using namespace std;
LL T,ans;
LL a,b,d;
LL sum[50010];
//LL nxt[50010];
short miu[50010];
LL prime[50010];
bool no_prime[50010];
inline LL in(){
LL ans=0;
char x=getchar();
while(x<'0'||x>'9')x=getchar();
while(x>='0'&&x<='9'){ans=ans*10+x-'0';x=getchar();}
return ans;
}
void f(){
if(a>b)swap(a,b);
for(LL i=1,it;i<=a;i=it+1){
it=Min(a/(a/i),b/(b/i));
ans+=((a/i))*((b/i))*(sum[it]-sum[i-1]);
}
}
int main(){
scanf("%lld",&T);
miu[1]=1;
for(LL i=2;i<=50001;i++){
if(!no_prime[i]){
prime[++prime[0]]=i;
miu[i]=-1;
}
for(LL j=1;prime[j]*i<=50001;j++){
no_prime[prime[j]*i]=true;
if(i%prime[j]==0){
miu[prime[j]*i]=0;
break;
}
miu[prime[j]*i]=-miu[i];
}
}
// for(LL i=1;i<=50001;i++)if(miu[i]!=0)nxt[++nxt[0]]=i;
for(LL i=1;i<=50001;i++)sum[i]+=sum[i-1]+miu[i];
while(T--){
ans=0;
a=in();b=in();d=in();
a/=d;b/=d;
f();
// LL minx=Min(a,b);
// LL tmp=0;
// while(1){
// tmp++;
// LL rk=d*nxt[tmp];
// if(rk>minx)break;
// ans+=miu[nxt[tmp]]*((a/rk)*(b/rk));
// }
printf("%lld\n",ans);
}
return 0;
}