小M的区间公约数
Time Limit: 1 s | Memory Limit: 64 MB
Difficulty: 1
Description
小M对最大公约数已经很熟悉了,今天突发奇想,她想知道区间最大的公约数。两个数a,b,然后有n组询问,每组询问[L,R],输出[L,R]区间中a,b最大的公约数,没有输出-1。
Input
多组测试数据 第一行输入a,b, (1 ≤ a, b ≤ 10^9) 第二行输入n,(1 ≤ n ≤ 10^4) 然后接下来n行,每行[L,R]。(a ≤ L ≤ R ≤ b)
Output
输出每次询问的结果。
Sample Input
9 27 3 1 5 10 11 9 11
Sample Output
3 -19
刚开始一看题目就觉得是用树状数组或线段树做,最后被告知不足要用这么高端的东西,哈哈,就是小技巧的处理,然后加一些优化,可见动用自己的脑筋该有多重要啊,bingo,这里的题解就是,先找出两个数的最大公约数,然后再把最大公约数的公约数存起来,这样存起来的数也是这两个数的公约数了,其中存的时候有一个小技巧,打个比方,这里9是最大公约数,然后它的公约数是1,3, 9,这里1*9=(sqrt(9))^2, 3*3=(sqrt(9))^2,明白了吗,就是一次性可以标记两个公约数,下面贴上代码
#include <iostream> #include <cstdio> #include <cmath> using namespace std; int num[100000];//因为这里最多不会超过sqrt(10^9),也许还能更少 int main() { int ma, mi, a, b, n, r; while(~scanf("%d%d", &a, &b)) { scanf("%d", &n); ma = a > b ? a : b; mi = a < b ? a : b; if(ma % mi != 0)//以下是求最大公约数,如果大数可以整除小数的话,那么最大公约数就是小数了,就不用进入计算了,节省时间 { r = ma % mi; while(r != 0) { ma = mi; mi = r; r = ma % mi; } }//最终最大公约数存在Mi中 int i, j = 0, first, last, cnt; for(i = 1; i <= sqrt(mi); i++)//这里就开始存公约数了,因为一次性存两个公约数,所以只需要遍历到sqrt(mi)就行了 { if(mi % i == 0) { num[j] = i; if(mi / i != i)//如果相等,只需要存一次 { num[++j] = mi / i; } j++; } } /* for(i = 0; i < j; i++) { printf("%d\t", num[i]); }*/ while(n--) { cnt = 0; ma = 1; scanf("%d%d", &first, &last); for(i = 0; i < j; i++)//下面的就是遍历了,是不是很简单,哈哈 { if(num[i] >= first && num[i] <= last) { if(ma < num[i]) { ma = num[i]; } cnt++; } } if(cnt != 0) { printf("%d\n", ma); } else { printf("-1\n"); } } } return 0; }