每日一题_小M的区间公约数_数论
小M的区间公约数 Time Limit:1 Ms| Memory Limit:10 MB Difficulty:0 [Problem] [Rank] 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]。(1 ≤ L ≤ R ≤ 10^9) Output 输出每次询问的结果。 Sample Input 9 27 3 1 5 10 11 9 11 Sample Output 3 -1 9
这个题目如果是在不考虑极限情况的时候,是挺简单的,就是先计算这两个数的真正的最大公约数,然后这个和区间的相对情况进行比较。
当最大公约数大于这个区间的时候,就用到了穷举,从区间的右端点开始直到左端点,当然这个应该是比较浪费时间的。
如果不是这样做的话,就是应该把这两个数的所有的约数都计算出来(计算约数只要算到根号下这个数就行了),然后进行处理,找到共同的,也就是这两个数的约数,
然后和这个区间进行比对。
但是这样的话,还是有些麻烦,后来发现,两个数的最大公约数的约数就是这两个数的约数,这样计算最大公约数的约数就好了,还不用去比较和去重了。
代码:
#include <stdio.h> #include <string.h> #include <stdlib.h> int gcd(int a, int b) { if (b == 0) { return a; } else { return gcd(b, a % b); } } int cmp_1(const void *a, const void *b) { return *(int *) a - *(int *) b; } int arr[10000]; int main() { int a, b; int n; int l, r; int i, j; int c; int top; int flag; while (scanf("%d%d", &a, &b) != EOF) { top = 0; memset(arr, -1, sizeof(arr)); //计算a和b的最大公约数 if (a >= b) { c = gcd(a, b); } else { c = gcd(b, a); } //求最大公约数的约数 for (j = 1; j * j <= c; j++) { if (c % j == 0) { arr[top++] = j; arr[top++] = c / j; } } //然后排序 qsort(arr, top, sizeof(int), cmp_1); scanf("%d", &n); while (n--) { flag = 1; scanf("%d%d", &l, &r); if (c < l) { printf("-1\n"); } else if (c >= l && c <= r) { printf("%d\n", c); } else { for (j = top - 1; j >= 0; j--) { if (arr[j] >= l && arr[j] <= r) { flag = 1; printf("%d\n", arr[j]); break; } } if (flag == 0) { printf("-1\n"); } } } } return 0; }
这个题目还要注意的就是有的计算可能很多组数据只需要计算一次,别放错地方,浪费时间。比如这个题的计算最大公约数的约数,不用放在while(n--)中,在外面就可以的。