AcWing4199.公约数

输入样例:
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]);
            } 

        }
    }
}

  • 16
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值