1. 问题描述:
给定两个正整数 a 和 b。你需要回答 q 个询问。每个询问给定两个整数 l,r,你需要找到最大的整数 x,满足:x 是 a 和 b 的公约数。l ≤ x ≤ r。
输入格式
第一行包含两个整数 a,b。第二行包含一个整数 q。接下来 q 行,每行包含两个整数 l,r。
输出格式
每个询问输出一行答案,即满足条件的最大的 x,如果询问无解,则输出 −1。
数据范围
前六个测试点满足 1 ≤ a,b ≤ 100,1 ≤ q ≤ 20。
所有测试点满足 1 ≤ a,b ≤ 10 ^ 9,1 ≤ q ≤ 10 ^ 4,1 ≤ l ≤ r ≤ 10 ^ 9。
输入样例:
9 27
3
1 5
10 11
9 11
输出样例:
3
-1
9
来源:https://www.acwing.com/problem/content/description/4202/
2. 思路分析:
分析题目可以知道我们需要求解a和b的最大公约数的约数x,求解出在[l,r]范围内最大的x;如果一个数d能整除a和b的最大公约数那么d能够整除a,并且d能够整除b,但是反过来如何证明呢?这里可以借助于算数基本定理来证明:
所以我们可以计算得到a,b最大公约数的约数,然后二分找到小于等于r的最大的那个整数即可,可以使用试除法来求解一个数的约数。
3. 代码如下:
在本地pycharm运行极限数据不会发生异常但是提交到acwing上发生了段错误,还有两个数据没过
from typing import List
class Solution:
# 求解a, b的最大公约数
def gcd(self, a: int, b: int):
return a if b == 0 else self.gcd(b, a % b)
# 试除法求解x的所有约数
def get_divisors(self, x: int):
i = 1
res = list()
while i * i <= x:
if x % i == 0:
res.append(i)
if i != x // i:
res.append(x // i)
i += 1
# 二分需要列表是有序的所以需要从小到大排序
res.sort()
return res
def process(self):
a, b = map(int, input().split())
d = self.gcd(a, b)
ds = self.get_divisors(d)
n = int(input())
for i in range(n):
L, R = map(int, input().split())
k = -1
l, r = 0, len(ds) - 1
# 二分找到小于等于r的最大数, 这里使用k来记录答案的位置
while l <= r:
mid = l + r >> 1
if ds[mid] <= R:
l = mid + 1
k = mid
else:
r = mid - 1
if L <= ds[k] <= R:
print(ds[k])
else:
print(-1)
if __name__ == '__main__':
Solution().process()