【NOIP提高组】Hankson的趣味题
💐The Begin💐点点关注,收藏不迷路💐 |
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整除。
输出
每组输入数据的输出结果占一行,为一个整数。对于每组数据:若不存在这样的 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。
C++ 代码:
#include <iostream>
#include <cmath>// 求两个整数的最大公约数,使用欧几里得算法
int gcd(int a, int b) {// 如果b为0,那么a就是最大公约数,直接返回areturn b == 0? a : gcd(b, a % b);
}int main() {int T;// 用于存储输入数据的组数,从标准输入读取该值std::cin >> T;// 循环处理每组输入数据,每次循环处理一组数据while (T--) {int a0, a1, b0, b1;// 从标准输入读取一组数据,分别表示题目中的a0、a1、b0、b1std::cin >> a0 >> a1 >> b0 >> b1;// 计算中间变量p,p等于a0除以a1,用于后续条件判断int p = a0 / a1;// 计算中间变量q,q等于b1除以b0,用于后续条件判断int q = b1 / b0;int ans = 0;// 遍历b1的所有因子,通过遍历到sqrt(b1)来获取所有因子,因为因子是成对出现的for (int x = 1; x * x <= b1; x++) {if (b1 % x == 0) {// 检查当前因子x是否满足所有条件// 条件1:x能被a1整除if (x % a1 == 0) {// 计算x除以a1的值int tempXDivA1 = x / a1;// 检查x除以a1后与p的最大公约数是否为1if (gcd(tempXDivA1, p) == 1) {// 检查q与b1除以x后的最大公约数是否为1if (gcd(q, b1 / x) == 1) {ans++;}}}// 得到b1的另一个因子y,避免重复计算当x等于y的情况int y = b1 / x;if (x == y) continue;// 检查因子y是否满足所有条件// 条件1:y能被a1整除if (y % a1 == 0) {// 计算y除以a1的值int tempYDivA1 = y / a1;// 检查y除以a1后与p的最大公约数是否为1if (gcd(tempYDivA1, p) == 1) {// 检查q与b1除以y后的最大公约数是否为1if (gcd(q, b1 / y) == 1) {ans++;}}}}}// 输出满足条件的x的个数std::cout << ans << std::endl;}return 0;
}
C语言代码:
#include <stdio.h>
#include <math.h>// 求两个整数的最大公约数,使用欧几里得算法
int gcd(int a, int b) {// 如果b为0,那么a就是最大公约数,直接返回areturn b == 0? a : gcd(b, a % b);
}int main() {int T;// 用于存储输入数据的组数,从标准输入读取该值scanf("%d", &T);// 循环处理每组输入数据,每次循环处理一组数据while (T--) {int a0, a1, b0, b1;// 从标准输入读取一组数据,分别表示题目中的a0、a1、b0、b1scanf("%d%d%d%d", &a0, &a1, &b0, &b1);// 计算中间变量p,p等于a0除以a1,用于后续条件判断int p = a0 / a1;// 计算中间变量q,q等于b1除以b0,用于后续条件判断int q = b1 / b0;int ans = 0;// 遍历b1的所有因子,通过遍历到sqrt(b1)来获取所有因子,因为因子是成对出现的for (int x = 1; x * x <= b1; x++) {if (b1 % x == 0) {// 检查当前因子x是否满足所有条件// 条件1:x能被a1整除if (x % a1 == 0) {// 计算x除以a1的值int tempXDivA1 = x / a1;// 检查x除以a1后与p的最大公约数是否为1if (gcd(tempXDivA1, p) == 1) {// 检查q与b1除以x后的最大公约数是否为1if (gcd(q, b1 / x) == 1) {ans++;}}}// 得到b1的另一个因子y,避免重复计算当x等于y的情况int y = b1 / x;if (x == y) continue;// 检查因子y是否满足所有条件// 条件1:y能被a1整除if (y % a1 == 0) {// 计算y除以a1的值int tempYDivA1 = y / a1;// 检查y除以a1后与p的最大公约数是否为1if (gcd(tempYDivA1, p) == 1) {// 检查q与b1除以y后的最大公约数是否为1if (gcd(q, b1 / y) == 1) {ans++;}}}}}// 输出满足条件的x的个数printf("%d\n", ans);}return 0;
}
Java代码:
import java.util.Scanner;public class Main {// 求两个整数的最大公约数,使用欧几里得算法public static int gcd(int a, int b) {// 如果b为0,那么a就是最大公约数,直接返回areturn b == 0? a : gcd(b, a % b);}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int T = scanner.nextInt();// 循环处理每组输入数据,每次循环处理一组数据while (T-- > 0) {int a0 = scanner.nextInt();int a1 = scanner.nextInt();int b0 = scanner.nextInt();int b1 = scanner.nextInt();// 计算中间变量p,p等于a0除以a1,用于后续条件判断int p = a0 / a1;// 计算中间变量q,q等于b1除以b0,用于后续条件判断int q = b1 / b0;int ans = 0;// 遍历b1的所有因子,通过遍历到sqrt(b1)来获取所有因子,因为因子是成对出现的for (int x = 1; x * x <= b1; x++) {if (b1 % x == 0) {// 检查当前因子x是否满足所有条件// 条件1:x能被a1整除if (x % a1 == 0) {// 计算x除以a1的值int tempXDivA1 = x / a1;// 检查x除以a1后与p的最大公约数是否为1if (gcd(tempXDivA1, p) == 1) {// 检查q与b1除以x后的最大公约数是否为1if (gcd(q, b1 / x) == 1) {ans++;}}}// 得到b1的另一个因子y,避免重复计算当x等于y的情况int y = b1 / x;if (x == y) continue;// 检查因子y是否满足所有条件// 条件1:y能被a1整除if (y % a1 == 0) {// 计算y除以a1的值int tempYDivA1 = y / a1;// 检查y除以a1后与p的最大公约数是否为1if (gcd(tempYDivA1, p) == 1) {// 检查q与b1除以y后的最大公约数是否为1if (gcd(q, b1 / y) == 1) {ans++;}}}}}// 输出满足条件的x的个数System.out.println(ans);}scanner.close();}
}
Python代码:
# 求两个整数的最大公约数,使用欧几里得算法
def gcd(a, b):# 如果b为0,那么a就是最大公约数,直接返回areturn a if b == 0 else gcd(b, a % b)T = int(input())while T:T -= 1a0, a1, b0, b1 = map(int, input().split())# 计算中间变量p,p等于a0除以a1,用于后续条件判断p = a0 / a1# 计算中间变量q,q等于b1除以b0,用于后续条件判断q = b1 / b0ans = 0# 遍历b1的所有因子,通过遍历到sqrt(b1)来获取所有因子,因为因子是成对出现的for x in range(1, int(b1 ** 0.5) + 1):if b1 % x == 0:# 检查当前因子x是否满足所有条件# 条件1:x能被a1整除if x % a1 == 0:# 计算x除以a1的值tempXDivA1 = x / a1# 检查x除以a1后与p的最大公约数是否为1if gcd(tempXDivA1, p) == 1:# 检查q与b1除以x后的最大公约数是否为1if gcd(q, b1 / x) == 1:ans += 1# 得到b1的另一个因子y,避免重复计算当x等于y的情况y = b1 / xif x == y:continue# 检查因子y是否满足所有条件# 条件1:y能被a1整除if y % a1 == 0:# 计算y除以a1的值tempYDivA1 = y / a1# 检查y除以a1后与p的最大公约数是否为1if gcd(tempYDivA1, p) == 1:# 检查q与b1除以y后的最大公约数是否为1if gcd(q, b1 / y) == 1:ans += 1# 输出满足条件的x的个数print(ans)
💐The End💐点点关注,收藏不迷路💐 |