试题描述
Hanks博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson。现在,刚刚放学回家的Hankson正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数c1和c2的最大公约数和最小公倍数。现在Hankson认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a0,a1,b0,b1,设某未知正整数x满足:
1.x和a0的最大公约数是a1;
2.x和b0的最小公倍数是b1。
Hankson的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的x并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x的个数。请你帮助他编程求解这个问题。
输入格式
第一行为一个正整数n,表示有n组输入数据。接下来的n行每行一组输入数据,为四个正整数a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入数据保证a0能被a1整除,b1能被b0整除。
输出格式
共n行。每组输入数据的输出结果占一行,为一个整数。
对于每组数据:若不存在这样的x,请输出0;
若存在这样的x,请输出满足条件的x的个数;
输入示例
2
41 1 96 288
95 1 37 1776
输出示例
6
2
说明
第一组输入数据,x可以是9、18、36、72、144、288,共有6个。
第二组输入数据,x可以是48、1776,共有2个。
注释说明
对于50%的数据,保证有1≤a0,a1,b0,b1≤10000且n≤100。
对于100%的数据,保证有1≤a0,a1,b0,b1≤2,000,000,000且n≤2000。
#include<cstdio>
using namespace std;
typedef long long ll;
ll n,a0,a1,b0,b1,ans=1;
ll prime[500005],cnt;
bool off[500005];
inline void input(ll &x){
ll ans=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+ll(c-48);
c=getchar();
}
x=ans*f;
}
inline void output(ll x){
if(x<0)putchar('-'),x=-x;
if(x>9)output(x/10);
putchar(char(x%10+48));
}
inline void euler(){
off[0]=off[1]=1;
for(ll i=1;i<=50000;i++){
if(!off[i])prime[++cnt]=i;
for(ll j=1;j<=cnt&&i*prime[j]<=50000;j++){
off[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
inline void work(ll x){
ll ina0=0,ina1=0,inb0=0,inb1=0;
while(a0%x==0)a0/=x,ina0++;
while(a1%x==0)a1/=x,ina1++;
while(b0%x==0)b0/=x,inb0++;
while(b1%x==0)b1/=x,inb1++;
if(ina0<ina1||inb0>inb1)ans=0;
if(ina0>ina1){
if(inb0<inb1){
if(ina1==inb1)ans*=1;else ans=0;
}
else if(inb0==inb1){
if(ina1<=inb1)ans*=1;else ans=0;
}
}
if(ina0==ina1){
if(inb0<inb1){
if(ina1<=inb1)ans*=1;else ans=0;
}
else if(inb0==inb1){
if(ina1<=inb1)ans*=(inb1-ina1)+1;
else ans=0;
}
}
}
int main(){
euler();
input(n);
for(ll i=1;i<=n;i++){
ans=1;
input(a0);input(a1);input(b0);input(b1);
//gcd(x,a0)=a1;
//lcm(x,b0)=b1;
for(ll i=1;i<=cnt;i++){
work(prime[i]);
}
if(b1!=1)work(b1);
output(ans);
putchar('
');
}
}