输入样例:
9 27
3
1 5
10 11
9 11
输出样例:
3
-1
9
思路分析:题目要求我们a和b的公约数,并获得 l-r之间的最大且是ab公约数的整数
暴力的时间复杂度:10000次询问 求a和b的公约数是根号下10的9次方
大概是3亿 会超时
其实每个数的约数个数是比较少的,int最大的数是2147483647,约数最多的数是2095133040,其约数个数是1600多,如果在10的9次方范围内,约数最多的个数是1300+
先预处理a和b的所有约数,这样就不用重复求
d是a和b的最大公约数,a和b的所有公约数x都可以整除d
可以用算术基本定理来证明
证明出每个公约数是最大公约数的约数
求a和b的最大公约数用欧几里得算法
static int gcd(int a,int b) {
return a<b?gcd(b,a):b==0?a:gcd(a%b,b);
}
//或者下面这种写法也ok
//传入的x一定大于等于y
static int gcd(int x, int y) {
return y != 0 ? gcd(y, x % y) : x;
}
然后用试除法求最大公约数的所有约数
最后搜索出所有符合条件的约数,可以直接暴力,或者用二分
实现代码:
import java.util.Scanner;
import java.util.Arrays;
public class Main {
static int N = (int) 1e6 + 10;
static int a, b, cnt;
static int aa[] = new int[N];
static int gcd(int x, int y) {
return y != 0 ? gcd(y, x % y) : x;
}
// 用最大公约数,做试除法,求所有约数
static void divide(int x) {
int tt = x;
aa[++cnt] = 1;
for (int i = 2; i <= x / i; i++) {
if (x % i == 0) {
aa[++cnt] = i;
if (i * i != x) {
aa[++cnt] = x / i;
}
}
}
aa[++cnt] = tt;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
a = in.nextInt();
b = in.nextInt();
int d = gcd(a, b);
divide(d);
Arrays.sort(aa, 1, cnt + 1);
int n = in.nextInt();
for (int i = 0; i < n; i++) {
int l = in.nextInt();
int r = in.nextInt();
int ll = 1, rr = cnt;
if (r < 1 || l > aa[cnt]) {
System.out.println(-1);
continue;
}
// 二分优化查询
while (ll < rr) {
int mid = ll + rr + 1 >> 1;
if (aa[mid] <= r) {
ll = mid;
} else {
rr = mid - 1;
}
}
if (aa[ll] < l ) {
System.out.println(-1);
} else {
System.out.println(aa[ll]);
}
}
}
}