题解 CF75C 【Modified GCD】
实际发表时间:2020-04-27
https://www.luogu.com.cn/problem/CF75C
没有用\(upper\,\_\,bound\)的题解?
那我来一篇吧~
思路:预处理公约数,再二分查找
预处理公约数:
我们知道,\(a,b\)任何一个公约数都能整除\(\gcd(a,b)\),那么,怎么证明呢?
证明:
分解质因数,\(a=p_1\times p_2\times \cdots \times p_x,b=q_1\times q_2\times\cdots\times q_y\)
根据公约数的定义,\(a,b\)的任意公约数\(x\)一定是集合\(p,q\)的相同元素集合\(r\)中的乘积组合\(r_{i_1}\times r_{i_2}\times\cdots\times r_{i_k}\).
那么\(\gcd(a,b)=r_1\times r_2\times\cdots\times r_z\),即\(r\)的所有元素之积。则\(x=r_{i_1}\times r_{i_2}\times\cdots\times r_{i_k}\)一定被包含在\(\gcd(a,b)=r_1\times r_2\times\cdots\times r_z\)之中。
即\(a,b\)任意公约数\(x | \gcd(a,b)\),证毕。
很好,那么我们只枚举\(\gcd(a,b)\)的因数即可。
我们从\(1\)枚举到\(\left\lfloor \sqrt{\gcd(a,b)} \right\rfloor\),把\(i\)和\(\dfrac{\gcd(a,b)}{i}\;push\,\_\,back\)进一个\(vector\)即可。
二分查找
先把\(vector:v\)排序,方便查找.
每次输入\(x,y\)时,设\(pos=upper\,\_\,bound(v.begin(),v.end(),y)-v.begin()\).
因为\(upper\_bound(v.begin(),v.end(),y)\)的返回值为\(v\)中第一个大于\(y\)的数的地址,若没找到返回\(v.end()\),复杂度\(\mathcal{O}(log\,_2n)\).
则按理来说\(v_{pos-1}\)就是要找的数
那么,就有两种情况:
- \(v_{pos-1}<x\),则它小于\(x\),输出\(-1\)
- 找到了,输出\(v_{pos-1}\)
代码
#include<bits/stdc++.h>
using namespace std;
int a,b,x,y,g;
vector<int>v;
int main()
{
scanf("%d%d",&a,&b);
g=__gcd(a,b);//求gcd(a,b)
for(int i=1;i*i<=g;i++)if(g%i==0)v.push_back(i),v.push_back(g/i);//找公约数
scanf("%d",&a);
sort(v.begin(),v.end());//排序
while(~scanf("%d%d",&x,&y))
{
int pos=upper_bound(v.begin(),v.end(),y)-v.begin();//二分查找
if(v[pos-1]<x)puts("-1");//没找到
else printf("%d\n",v[pos-1]);//找到了
}
return 0;
}

浙公网安备 33010602011771号