bzoj1876 [SDOI2009]SuperGCD
1876: [SDOI2009]SuperGCD
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 3744 Solved: 1349
[Submit][Status][Discuss]
Description
Sheng bill有着惊人的心算能力,甚至能用大脑计算出两个巨大的数的GCD(最大公约 数)!因此他经常和别人比
赛计算GCD。有一天Sheng bill很嚣张地找到了你,并要求和你比 赛,但是输给Sheng bill岂不是很丢脸!所以你
决定写一个程序来教训他。
Input
共两行: 第一行:一个数A。 第二行:一个数B。
0 < A , B ≤ 10 ^ 10000。
Output
一行,表示A和B的最大公约数。
Sample Input
12
54
54
Sample Output
6
HINT
Source
分析:这道题是一道非常烦人的高精度问题,求gcd谁都会,但是直接用欧几里得算法,高精度取模直接gg,而且还是压位的,打出来估计要半天.那么换一种方法:更相减损术:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。 ----摘自百度百科
也就是说我们只需要设计乘法,除法和减法就可以了。高精度算法就相当于模拟我们算术一样,只不过用程序跑而已,步骤是先操作,再进位、补位,最后看数组的长度有没有改变.
这道题一定要压位来处理,不然会tle,压位后的操作与没有压位差不多,只不过mod的数变了,以前是逢10进1,现在是逢n进1.
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<map> using namespace std; const int mod = 100000000; int tot; struct node { int x[2010], len; }a,b; void read(node &c) { char s[10010]; scanf("%s", s); int len = strlen(s),cnt = 0,chengji = 1; for (int i = len - 1; i >= 0; i--) { cnt = cnt + (s[i] - '0')* chengji; chengji *= 10; if ((len - i) % 8 == 0) { c.x[++c.len] = cnt; cnt = 0; chengji = 1; } } if (cnt != 0) c.x[++c.len] = cnt; } void div1() { for (int i = a.len; i >= 1; i--) { if (a.x[i] % 2 == 1) a.x[i - 1] += mod; a.x[i] >>= 1; } while (a.x[a.len] == 0 && a.len > 1) a.len--; } void div2() { for (int i = b.len; i >= 1; i--) { if (b.x[i] % 2 == 1) b.x[i - 1] += mod; b.x[i] >>= 1; } while (b.x[b.len] == 0 && b.len > 1) b.len--; } bool check() { if (a.len != b.len) return false; for (int i = 1; i <= a.len; i++) if (a.x[i] != b.x[i]) return false; return true; } bool cmp() { if (a.len > b.len) return true; else if (a.len < b.len) return false; for (int i = a.len; i >= 1; i--) { if (a.x[i] > b.x[i]) return true; else if (a.x[i] < b.x[i]) return false; } return true; } void jian(node &c, node d) { for (int i = 1; i <= c.len; i++) { if (c.x[i] >= d.x[i]) c.x[i] -= d.x[i]; else { c.x[i] = c.x[i] + mod - d.x[i]; c.x[i + 1]--; } } while (c.x[c.len] == 0 && c.len > 1) c.len--; } void mul() { for (int i = 1; i <= a.len; i++) a.x[i] <<= 1; for (int i = 1; i <= a.len; i++) if (a.x[i] >= mod) { a.x[i] -= mod; a.x[i + 1]++; } while (a.x[a.len + 1]) a.len++; } void print() { printf("%d", a.x[a.len]); for (int i = a.len - 1; i >= 1; i--) printf("%08d", a.x[i]); printf("\n"); } int main() { read(a); read(b); while (a.x[1] % 2 == 0 && b.x[1] % 2 == 0) { tot++; div1(); div2(); } while (!check()) { if (cmp()) jian(a, b); else jian(b, a); while (a.x[1] % 2 == 0) div1(); while (b.x[1] % 2 == 0) div2(); } while (tot--) mul(); print(); return 0; }