[最大公约数] 问题列表#1574 #1181
最大公约数的求法
最大公约数——辗转相除法(欧几里得算法)
给定两个数 a,b 求最大公约数。使用辗转相除法思路如下:
-
对于已知的两个自然数 a,b 假设 a>b。
-
计算 a/b 将得到的余数记为 r
-
如果 r=0 ,则 b 为求得的最大公约数,否则执行下一步
-
将 b 的值保存到 a 中,将 r 的值保存到 b 中,重复执行(2)(3),直到 r=0 ,便得到最大公约数。
将代码简化,扩大范围到 long long 则代码如下:
long long gcd(long long a,long long b) { return !b ? a : gcd(b, a%b); }
最大公约数——Stein 算法
欧几里得算法简单的同时也具有很高的效率,但如果计算的数超过32位,往往需要反复试商,效率大大降低。
改进:
Stein 算法只有整数的移位和加减法,首先注意以下结论:gcd(a,a) = a,也就是一个数和他自身的公约数是其自身,gcd(ka,kb) = k gcd(a,b),也就是最大公约数运算和倍乘运算可以交换,特殊的,当k=2时,说明两个偶数的最大公约数必然能被2整除。
Stein算法其实是分类减小的思想,和欧几里得算法其实差不太多,主要是为了缩小那两个数,一共分三种情况:
-
两个都是偶数的情况,这个时候的做法是将这两个数都减半,例如现在要求6和8的最大公约数,那么其实求到3和4的最大公约数再乘上2就好了。
-
一个奇数一个偶数的情况,这种情况只将偶数减半就好,因为最大公约数肯定是奇数。
-
两个都是奇数的情况,这个时候有两个做法:一个是转为求 A-B 和 B(两个数中小的那个)的最大公约数。另一种做法是转为求 (A+B)/2, (A-B)/2 的最大公约数,其实都是可以的。
把乘2改写成左移一位,除以2改写成右移一位,这样就可以精简代码:
long long GCD(long long a, long long b) { if (a == b) return a; if (a == 0) return b; if (b == 0) return a; long long k = 0; while ((a & 1) == 0 && (b & 1) == 0) { a = a >> 1; b = b >> 1; k++; } while ((a & 1) == 0) a = a >> 1; while ((b & 1) == 0) b = b >> 1;//转为两数都是奇数的情况 return GCD(abs(a - b) >> 1, min(a, b) << k); //或者写为:return GCD((a+b)>>1,abs(a-b)>>1); }
以上就是全部的拓展内容啦,下面就去写题目吧!
《1574:韩信又点兵》
题意:
一支军队总人数不大于100万。让士兵按每排A1人排成纵队,发现最后余了1个士兵;每排A2人,也是多1个士兵;...;每排Am人,也是多一个士兵。请求出满足条件的最大数字。如果无解,则输出-1。
题解:
例如对于 a,b,c 三个数求最大解:
- 输入 a,b 求 a,b 的最小公倍数 m
- 输入 c ,求 c 和 m 的最小公倍数,得到 n
- 对 n 反复自加 n,直到大于或等于100w
- 取上一次的数据,加1后输出。
上板子:
#include<bits/stdc++.h> using namespace std; typedef long long ll; long long gcd(long long a, long long b) { return !b ? a : gcd(b, a % b); } int main() { int n; cin >> n; while(n--)//n组案例 { ll m, a, b, c;//m个数字,ab为两个数,c为两数的最大公因数 cin >> m >> a;//先读一个数a m -= 1; while (m > 0)//当还有数字未读 { cin >> b; if (a < 1000000) { c = gcd(a, b); a = a * b / c; } m--; } if (a >= 1000000 || m < 0)cout << -1 << endl; else { ll u = a; while (a < 1000000) { a += u; } cout << a - u + 1 << endl; } } return 0; }
《1181:公因数》
题意:
输入两个正整数m和n,输出它们所有的公因数。
题解:
例如对于 m,n 求所有公因数:
- 求出 m,n 的最大公因数 q
- 求在 [1,q] 范围内的所有公因数
各种思路:
- 使用 set 存储所有的公因数(可以自动排序,最后使用迭代器输出)
- 使用 sqrt(q),缩小范围求公因数 //一个数对应一个数,例如对于 12,当判断1时同时存储 12/1,判断2时同时存储 12/2,判断到sqrt(12)为止。
- 可以先输出较小的数(<=sqrt(q)),将较大的数存储后倒序输出。
制作:BDT20040