原题连接:4199. 公约数 - AcWing题库

题意:给定 a,b ,在每次询问的区间中找到 a, b 的最大的公约数,不存在输出 -1

思路

预处理

实际上数据范围并没有非常大,在每次询问前预处理 a b 的公约数就可以

怎么找两个数的公约数呢?

理论

两个数的约数可以整除其最大公约数

证明:

Transclude of 数学#^eff2d8

利用定理可以发现,两数的最大公约数必定可以表示为公共质因数的幂的乘积的形式

而两者约数也可以,即公约数必定可以整除最大公约数

试除法找约数即可

实现

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
 
using namespace std;
 
 
vector<int> g;
 
int a, b;
int q, l, r;
 
int gcd(int a, int b)
{
    return b?gcd(b, a % b):a;
}
 
 
int main()
{
    cin >> a >> b;
    //预处理a,b公约数
    
    int mg = gcd(a, b);
    
    for(int i = 1; i <= mg / i; i ++)
    {
        if(mg % i == 0)
        {
            g.push_back(i);
            if(i != mg / i) g.push_back(mg / i);
        }
    }
    
    
    //sort(g.begin(), g.end(), greater<int>() );
    sort(g.begin(), g.end());
    
    cin >> q;
    
    while(q --)
    {
        cin >> l >> r;
        
        /*暴力可以写
        int flag = 0;
        for(int i = 0; i < g.size(); i ++)
        {
            if(g[i] <= r && g[i] >= l)
            {
                flag = 1;
                cout << g[i] << endl;
                break;
            }
        }
        */
        //双指针优化
        int L = 0, R = g.size() - 1;
        
        while(L < R)
        {
            int mid = L + R + 1 >> 1;
            if(g[mid] <= r) L = mid;
            else R = mid - 1;
        }
        
        if(g[L] < l) cout << "-1" << endl;
        else cout << g[L] << endl;
        
        //if(!flag) cout << "-1" << endl;
    }
    
    return 0;
}

思路活一点,就算不用最大公约数,这道题也就可以在合理时间内试除法找公约数