最大公约数,最小公倍数我们非常熟悉,并且很常用,一般来说,我们最常用的方法就是辗转相除法,初学者光看代码很难彻底理解辗转相除法的原理,接下来everybody请欣赏铭哥的表演;
例如 15, 9 这两个数的最大公约数(gcd) ,how to 求?
LL GCD(LL c, LL b){
if (c < b){
LL temp = b; //c 必须大于 b
b = c;
c = temp;
}
LL ans = 0;
while (b != 0){
ans = c % b;
//cout << "c = " << c << " b = " << b << endl;
c = b;
b = ans;
}
return c;
}
c是15, b是9, 难懂的地方就在while里,
咱们将问题图像化, 15, 9的最大公约数就是长15宽9的长方形里,每一次都砍掉长方形内部最大的正方形, 最后剩下的最小正方形的边长就是最大公约数,
比如目前最大的正方形是边长为9, 接下来原来的图形变为长为9,宽为6,再砍掉边长为6的正方形,变为长为6,宽为3,再砍掉边长为3的正方形,原图像就变成了3 * 3大小的正方形了, 3就是最大公约数;只要记得这个图,以后写最大公约数的函数时就随便写了;
最小公倍数求法, (a * b) / gcd(a, b);
同时,c++也提供了api ,就是 __gcd(a, b); a,b 都必须是int型的,so 如果a,b太大就不能用了,老老实实的写函数吧;
当然, 各位竞赛的时候可能经常会遇到要同时求很多很多个数的最大公约数and最小公倍数;这个就简单了,献上代码;
LL c = b[1];
for (int i = 1; i <= n - 1; i ++){
c = GCD(c, b[i]);
}
设置一个变量c, 一直跟b数组中的每一个数求最大公约数就欧克了;(i <= n - 1 这个不要理会应该是小于n 这个是下面的例题中的一段代码);
例题: 蓝桥杯:等差数列第14届蓝桥杯 Java 组省赛夺奖班【仅课程】 - 【学长带练】等差数列 - 蓝桥云课 (lanqiao.cn)
这道题解法就是将所有数从小到大排序 两两做差, n个差值求最大公约数, 有了最大公约数就解决了, 数组中最大数减去最小数除最大公约数 + 1就是答案了;
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL GCD(LL c, LL b){
if (c < b){
LL temp = b; //c 必须大于 b
b = c;
c = temp;
}
LL ans = 0;
while (b != 0){
ans = c % b;
c = b;
b = ans;
}
return c;
}
int main (){
int n;
cin >> n;
LL a[n + 1] = {0};
LL b[n] = {0};
for (int i = 1; i <= n; i ++){
cin >> a[i];
}
sort (a + 1, a + n + 1);
for (int i = 1; i <= n - 1; i ++){
b[i] = a[i + 1] - a[i];
}
// int c = b[1];
// for (int i = 1; i <= n - 1; i ++){
// c = __gcd(c, b[i]); // __gcd(int, int) 参数必须都是int类型的;
// }
// int temp = a[n] - a[1];
// if (c == 0) {
// cout << n << endl;
// return 0;
// }
// cout << temp / c + 1 << endl;
LL c = b[1];
for (int i = 1; i <= n - 1; i ++){
c = GCD(c, b[i]);
}
if (c == 0) {
cout << n << endl;
return 0;
}
LL temp = a[n] - a[1];
cout << temp / c + 1 << endl;
return 0;
}
这题的数据太大, 必须开long long 所以这道题不能用__gcd(a, b)函数,但是我在注释部分也补上了用__gcd(a, b)解题的方案,如果到竞赛时忘了GCD函数怎么写了就用__gcd(a, b)吧;