问题描述
输入格式
输出格式
样例输入
2
41 1 96 288
95 1 37 1776
样例输出
6
2
提示
数据范围
题解
显然直接枚举满足条件的x每次求gcd会超时,我们先尝试两个条件进行转化。
由条件1得gcd(x,a0)=a1
不妨设a1*k1=x ,a1*k2=a0
那么gcd(k1,k2)=1
证明:
假设gcd(k1,k2)=1不成立,那么k1,k2存在一个大于1的公因数m,则a1*k1/m*m=x,a1*k2/m*m=a0
由于m是k1,k2的公因数,所以k1/m,k2/m为整数
可得gcd(x,a0)=a1*m
与前面gcd(x,a0)=a1矛盾,所以假设不成立,那么gcd(k1,k2)=1是成立的
而k1=x/a1,k2=a0/a1,
进一步转化得gcd(x/a1,a0/a1)=1
这样我们得到了x,a1,a0的新的关系式
再看条件2,lcm(x,b0)=b1=x*b0/gcd(x,b0)
得gcd(x,b0)=x*b0/b1
这是一个和条件1相似的式子,类似地,可以转化为gcd(x/(x*b0/b1),b0/( x*b0/b1))=1
即gcd(b1/b0,b1/x)=1
结合gcd(x/a1,a0/a1)=1
我们可以先枚举找出b1的因数x,然后检验x是否是a1的倍数并且满足以上两个式子,即可找到满足条件的x。这样就减少了求gcd的次数,从而缩短了运行时间。
进一步优化,由埃氏筛法求素数得到启发,x的枚举范围不必从1到b1,若x是b1的因数,则b1/x也是b1的因数,所以x只需从1枚举到√x
1 #include <cstdio> 2 #include <cmath> 3 int n; 4 int a0,a1,b0,b1,s; 5 int gcd(int a,int b) 6 { 7 return b?gcd(b,a%b):a; 8 } 9 int read() // 读入优化 10 { 11 char c=getchar(); 12 int x=0; 13 while (c<'0' || c>'9') c=getchar(); 14 while (c>='0' && c<='9') 15 x=x*10+c-'0', 16 c=getchar(); 17 return x; 18 } 19 int main() 20 { 21 int i,j; 22 n=read(); 23 while (n--) 24 { 25 s=0; 26 a0=read(); a1=read(); b0=read(); b1=read(); 27 for (i=1;i*i<=b1;i++) 28 { 29 if (!(b1%i)) 30 { 31 j=b1/i; 32 if (!(i%a1) && gcd(i/a1,a0/a1)==1 && gcd(b1/b0,b1/i)==1) s++; 33 if (j!=i && !(j%a1) && gcd(j/a1,a0/a1)==1 && gcd(b1/b0,b1/j)==1) s++; 34 } 35 } 36 printf("%d ",s); 37 } 38 return 0; 39 }