题目链接:Hankson的趣味题
怎么讲呢?感觉这一题的难度给高了。
其实涉及的数学推理其实并不难,而且一旦数学推理结束,就是暴力枚举了,而且代码也短没什么难度。
所以我们就进行一下关键的数学分析。
我们要求x满足一下要求:
- (x,a0)=a1
- [x,b0]=b1
括号是什么意思,大家应该知道。
我们不妨设:
- x=m*a1
- a0=a*a1
- b1=n*x
- b1=b*b0
其中,m、a、n、b均为正整数。
分析条件1,可以得到(a,m)=1
分析条件2,可以得到(n,b)=1
再由我们设的式子可以得到:b1=m*n*a1
所以我们只要枚举m(因为m*n=b1/a1是一个定值),即可确定有多少个x。
因为x显然由m和n唯一确定,也就是两者一一对应(对应原理)
由m和n的乘积,我们知道b1/a1必须是个整数,所以我们可以判断一下,如果不是,直接输出0就行了。
接下来是枚举,由于数据比较大,我们可以采取每次枚举两对m和n,比如我们令up=b1/a1,枚举到i时,我们可以检验m=i、n=up/i和m=up/i、n=i,这样我们的i只需要枚举到i*i<=up即可,否则,如果你把i枚举到up,是会T的。
接下来,还要注意m==n的情况,不要重复计算。
所以,代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int a0,a1,b0,b1;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main(){
scanf("%d",&n);
while(n--){
int ans=0;
scanf("%d%d%d%d",&a0,&a1,&b0,&b1);
int a=a0/a1,b=b1/b0;
int up=b1/a1;
double check=(double)b1/(double)a1;
if(check!=(double)up){
printf("0\n");
continue;
}
for(int i=1;i*i<=up;i++){
if(up%i==0){
if((gcd(a,i)==1)&&(gcd(b,up/i)==1)){
ans++;
}
if((gcd(a,up/i)==1)&&(gcd(b,i)==1)){
if(i!=up/i){
ans++;
}
}
}
}
printf("%d\n",ans);
}
return 0;
}