洛谷P1072 Hankson的趣味题
这个问题是这样的:已知正整数 a 0 , a 1 , b 0 , b 1 a_0,a_1,b_0,b_1 a0,a1,b0,b1设某未知正整数 x x x 满足:
x x x 和 x 0 x_0 x0的最大公约数是 a 1 a_1 a1, x x x 和 b 0 b_0 b0 的最小公倍数是 b 1 b_1 b1。
Hankson 的“逆问题”就是求出满足条件的正整数 x。但稍加思索之后,他发现这样的 x 并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的 x 的个数。请你帮助他编程求解这个问题。
输入格式
第一行为一个正整数 n,表示有 n 组输入数据。接下来的n 行每行一组输入数据,为四个正整数
a
0
,
a
1
,
b
0
,
b
1
a_0,a_1,b_0,b_1
a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入数据保证
a
0
a_0
a0能被
a
1
a_1
a1 整除,
b
1
b_1
b1能被
b
0
b_0
b0 整除。
输出格式
共 n 行。每组输入数据的输出结果占一行,为一个整数。
对于每组数据:若不存在这样的 x,请输出 0,若存在这样的 x,请输出满足条件的 x 的个数;
输入输出样例:
输入#1:
2
41 1 96 288
95 1 37 1776
输出#1:
6
2
数据范围:
- 1 ≤ a 0 , a 1 , b 0 , b 1 ≤ 2 × 1 0 9 1\leq a_0,a_1,b_0,b_1\leq 2\times 10^9 1≤a0,a1,b0,b1≤2×109 且 n ≤ 2000 n\leq 2000 n≤2000.
题目的大意也很简单,就是要找这样的x。由于a和b都在整个int范围内,所以试图找到一个限制x的条件。在最大公约数和最小公倍数问题里,其实直接寻找整除关系就可以了:
g
c
d
(
x
,
a
0
)
=
a
1
⇒
a
1
∣
x
gcd(x,a_0)=a_1\quad \Rightarrow \quad a_1 | x
gcd(x,a0)=a1⇒a1∣x
l
c
m
(
x
,
b
0
)
=
b
1
⇒
x
∣
b
1
lcm(x,b_0)=b_1\quad \Rightarrow \quad x | b_1
lcm(x,b0)=b1⇒x∣b1
所以思路就出来了。穷举b_1的因数,这个因数范围在
I
N
T
_
M
A
X
\sqrt{INT\_ MAX}
INT_MAX内,穷举一个因数x的时候同时判断
b
1
x
\frac{b_1}{x}
xb1,就可以全部穷举一遍了。。还是要注意几个问题:
- x要用long,否则x*b0之类的会溢出
- x和y都要一起判断下
- 输出之前用的cout,居然1.02sT了。。。改成printf就好了
#include <bits/stdc++.h>
using namespace std;
int t;
int a0,a1,b0,b1;
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main(){
cin>>t;
while(t--){
scanf("%d %d %d %d",&a0,&a1,&b0,&b1);
int res=0;
for(long x=1;x*x<=b1;x++){
if(b1%x==0){
if(x%a1==0&&gcd(x,a0)==a1&&x*b0/gcd(x,b0)==b1) res++;
long y=b1/x;
if(x!=y){
if(y%a1==0&&gcd(y,a0)==a1&&y*b0/gcd(y,b0)==b1) res++;
}
}
}
printf("%d\n",res);
}
return 0;
}