问题
描述
已知正整数a0,a1,b0,b1,设某未知正整数x满足: 1、 x和a0的最大公约数是a1; 2、 x和b0的最小公倍数是b1。
Hankson的“逆问题”就是求出满足条件的正整数x的个数。
输入
输入第一行为一个正整数n,表示有n 组输入数据。 接下来的n 行每
行一组输入数据,为四个正整数a0,a1,b0,b1,每两个整数之间用一个空格隔开。输入 数据保证a0 能被a1 整除,b1 能被b0 整除。
输入样例:
2 41 1 96 288 95 1 37 1776
输出:
输出共n 行。每组输入数据的输出结果占一行,为一个整数。 对于每组数据:若不存在这样的 x,请输出0; 若存在这样的
x,请输出满足条件的x 的个数;
输出样例:
6
2
分析
一开始的做法是取a1的倍数,上限是b1,分别和a0,b0求最大公约数,最小公倍数,但提交后显示部分运行超时,没办法,百度后发现题没读完,
样例说明
第一组输入数据,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。
后来知道有这么个结论:
对于两个正整数a,b,设 gcd(a,b)=k,则存在gcd(a/k,b/k)=1
gcd(x/a1,a0/a1)=1
gcd(b1/b0,b1/x)=1
import java.util.Scanner;
同时,从a1的倍数出发枚举并不高效,改为从1开始,i * i <= b1结束。
代码
正解
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();// 数据组数
while ((n--) > 0) {
int cnt = 0;
int a0 = sc.nextInt();
int a1 = sc.nextInt();
int b0 = sc.nextInt();
int b1 = sc.nextInt();
// ----------------------------------
int p = a0 / a1;
int q = b1 / b0;
for (int i = 1; i * i <= b1; i++) {
if (b1 % i == 0) {
//判断两部分 b1 = x * y ,既判断x,同时也判断y,x就是i
if (gcd(i / a1, p) == 1 && gcd(q, b1 / i) == 1 && (i % a1 == 0))
cnt++;
int j = b1 / i;//这里的j相当于和i乘积等于b1的另外一个因数
if (i == j)
continue;
if (gcd(j / a1, p) == 1 && gcd(q, b1 / j) == 1 && (j % a1 == 0))
cnt++;
}
}
System.out.println(cnt);
}
}
// -----------------------------
private static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
}
原始版本:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] input = new int[n][4];
int[] res = new int[n];
// 数据输入
for (int i = 0; i < n; i++) {
for (int j = 0; j < 4; j++) {
input[i][j] = sc.nextInt();
}
}
for (int i = 0; i < n; i++) {
for (int j = input[i][1]; j <= input[i][3]; j += input[i][1]) {
if (divisor(j, input[i][0]) == input[i][1] && multiple(j, input[i][2]) == input[i][3])
res[i]++;
}
}
for (int i = 0; i < res.length; i++) {
System.out.println(res[i]);
}
}
private static int divisor(int x, int y)// 最大公约数
{
int temp = 0;
if (x < y) {
temp = x;
x = y;
y = temp;
}
if (x % y == 0)
return y;
while (y != 0) {
temp = x % y;
x = y;
y = temp;
}
return x;
}
private static int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
private static int multiple(int x, int y)// 最小公倍数
{
int temp;
temp = divisor(x, y);
return (x * y / temp);
}
}