4199 公约数(求解约数 + 最大公约数 + 二分)

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()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值