首页 > 技术文章 > nyoj 881 小M的区间公约数

z-y-p 2013-11-30 11:32 原文

点击打开链接


首先给的范围很大,是10^9。暴力解肯定超时(单用for循环到10^9都大约要2s-3s),首先写了个程序暴力的把两个数所有的约数都打印出来,最后发现所有的公约数都是最大公约数的约数,并且最大公约数的约数也一定是两个数的公约数,由此题目转换为求最大公约数的约数的问题,以为输入最大是10^9,所以公约数最大是5*10^8,求这个数的所有约数只需要循环到(跟号5)*10^4,for循环可以轻松应对了,直接用for得到所有的约数,然后qsort排序后,把数组的结构抽象成数轴上的n多个点,每个点都是这两个数的约数了,剩下的工作就是从大到小循环所有的公约数找第一个在查询区间里的约数就是要求的解。

附上AC代码:

#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(const void *a, const void *b)
{
    return *(int *)b - *(int *)a;
}
int array[10000];
int top;
int main()
{
    int a, b;
    while(scanf("%d %d", &a, &b) != EOF)
    {
        memset(array, 0, sizeof(array));
        top = 0;
        int n;
        if(a < b)
        {
            int swap = a;
            a = b;
            b = swap;
        }
        int max = gcd(a, b);
        int i;
        for(i = 1; i * i < max; i++)
        {
            if(max % i == 0)
            {
                array[top++] = i;
                array[top++] = max / i;
            }
        }
        if(i * i == max)
            array[top ++] = i;
        qsort(array, top, sizeof(int), cmp); 
        scanf("%d", &n);
        while(n--)
        {
            int l, r;
            scanf("%d %d", &l, &r);
            int k;
            if(l > max)
            {
                printf("-1\n");
                continue;
            }
            for(k = 0; k < top; k++)
            {
                if(l <= array[k] && r >= array[k])
                {
                    printf("%d\n", array[k]);
                    break;
                }
                else if(l > array[k])
                {
                    printf("-1\n");
                    break;
                }
            }
        }
    }
    return 0;
}


推荐阅读