约数

本文探讨了如何求解两个正整数的最大公约数,并在此基础上,提出了一种算法来寻找在指定范围内既能被X整除也能被Y整除的最大整数。通过对输入数据的预处理和排序,该算法能够高效地解决这一问题。

 约数

时间限制: 1 Sec  内存限制: 128 MB

题目描述

给出两个正整数X和Y,求X和Y的最大公约数,奶牛可以轻松解决这个问题。
农夫Farmer John决定改一改题目去考验奶牛。农夫决定询问奶牛Q个问题,每个问题的格式是这样的:
农夫给定两个正整数a和b,农夫保证a < = b,然后农夫询问奶牛:在a至b的范围内,有没有哪个整数既是X的约数同时又是Y的约数?如果有,输出最大的那个;如果没有,输出-1。

 

输入

第一行,两个正整数,X和Y。
第二行,一个整数数,Q。
接下来有Q行,每行两个正整数:a和b,其中保证a <= b。

 

 

输出

共Q行,每行一个整数,每行对应农夫的一个问题。

 

样例输入

复制样例数据

200  120
3
9  40
25  35
10  15

样例输出

40
-1
10

 

提示

第一个问题:在9至40的范围内,既是200的约数,同时又是120的约数,共有3个,分别是:10,20,40,在3个之中,40最大,所以输出40。
第二个问题:在25至35的范围内,找不到既是200的约数,同时又是120的约数,所以输出-1。
第三个问题:在10至15的范围内,既是200的约数,同时又是120的约数,只有10,所以输出10。

1、对于40%的数据,1<=X<=100,1 <= Y <= 100, 1 <= Q <= 100,1<=a<b<=100
2、对于100%的数据,1<=X<=1000000000,1 <= Y <= 1000000000, 1 <= Q <= 30000,1<=a<b<=1000000000。

求两个数的公约数,先与处理,然后排个序,从最大的开始往下找。

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

int x, y, n, a, b;
vector<int> vec;

int main()
{
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);

	scanf("%d %d", &x, &y);
	if(x > y) swap(x, y);
	int t = sqrt((double) x);
	for (int i = 1; i <= t; i++){
		if(x % i == 0 && i * i != x){
			if(y % i == 0) vec.push_back(i);
			if(y % (x / i) == 0) vec.push_back(x / i);
		}else if(x % i == 0 && y % i == 0) vec.push_back(i);
	}
	sort(vec.begin(), vec.end());
	int len = vec.size();
	scanf("%d", &n);
	for (int i = 1; i <= n; i++){
		scanf("%d %d", &a, &b);
		int flag = 0;
		for (int j = len - 1; j >= 0; j--){
			if(vec[j] <= b && vec[j] >= a){
				printf("%d\n", vec[j]);
				flag = 1;
				break;
			}else if(vec[j] < a) break;
		}
		if(!flag) printf("-1\n");
	}

	return 0;
}
/**/

 

计算一个数的所有约数可以通过多种方式实现,具体取决于需的复杂性性能要。以下是一些常见的方法实现细节。 ### 试除法 试除法是最直接的方法,通过遍历从1到该数本身的所有整数,并检查其是否能被整除。如果某个整数能够整除目标数,则它是一个约数。这种方法虽然简单,但在处理大数时效率较低。 例如,对于给定的整数 `a`,其所有约数可以通过以下逻辑找到: ```c #include <stdio.h> int main(int argc, char* argv[]) { int i, a; while (scanf("%d", &a) != EOF) { printf("%d 的约数有:", a); for (i = 1; i <= a; i++) { if (a % i == 0) { printf("%d ,", i); } } printf("\n"); } return 0; } ``` ### 优化算法 为了提高效率,可以对上述过程进行优化。考虑到一个数的约数成对出现的特点,只需遍历到该数的平方根即可[^3]。这样可以显著减少循环次数,特别是在处理较大的数字时。 ### 数学公式法 另一种方法是基于质因数分解来计算约数。首先将一个数分解为其质因数的乘积形式,然后利用这些质因数及其指数来生成所有的约数组合。这种方法通常用于需要快速获取所有约数的应用场景,尤其是当目标数非常大时。 假设有一个数 $ N $,其质因数分解形式为 $ p_1^{a_1} \cdot p_2^{a_2} \cdots p_n^{a_n} $,其中 $ p_i $ 表示第 $ i $ 个质因数,而 $ a_i $ 是对应的指数。根据这个表达式,可以通过如下步骤生成所有的约数: 1. 对于每个质因数 $ p_i $ ,考虑其可能取到的不同幂次 $ 0, 1, ..., a_i $。 2. 将各个幂次相乘得到不同的组合,每种组合对应一个唯一的约数。 此外,还可以利用这些信息快速计算出所有约数的数量以及它们的总: - 约数个数 $ d(N) = (a_1 + 1)(a_2 + 1)\cdots(a_n + 1) $ - 约数 $ S(N) = (1+p_1+p_1^2+\cdots+p_1^{a_1})(1+p_2+p_2^2+\cdots+p_2^{a_2})\cdots(1+p_n+p_n^2+\cdots+p_n^{a_n}) $ 这种方法不仅提供了关于约数的基本信息,而且为进一步分析提供了基础[^4]。 ### C++ 实现示例 下面给出了一段使用上述原理计算给定正整数约数个数的 C++ 代码片段: ```cpp #include<bits/stdc++.h> using namespace std; long long n, cnt = 1; int main() { cin >> n; for(long long i = 2; i * i <= n; i++) { long long num = 0; if(n % i == 0) { while(n % i == 0) { num++; n /= i; } cnt *= num + 1; } } if(n != 1) cnt *= 2; cout << cnt; return 0; } ``` 此程序首先尝试将输入值除以从小到大的每一个可能的因子,记录下每次成功分割后的次数。最后,依据质因数分解的结果计算出原始数值的所有约数数目[^5]。 以上就是几种常用的计算一个数所有约数的方法技术细节。选择哪种方法取决于具体应用场景的需以及对性能的要
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值