小m的区间公约数

小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
-1

9

刚开始一看题目就觉得是用树状数组或线段树做,最后被告知不足要用这么高端的东西,哈哈,就是小技巧的处理,然后加一些优化,可见动用自己的脑筋该有多重要啊,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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值