【SDOI2009】SuperGCD
本题在洛谷上的链接:https://www.luogu.org/problemnew/show/P2152
在做这道题之前,有位学长和我吹,他用10分钟两行代码就做完了。当时实在是吓到我了,自己做完这道题,好奇就去看看学长的代码,,,原来是Python。。。
求最大公约数可以选择辗转相除法或者更相减损术,这道题最好是选择更相减损术,一个是相对较快,一个是适合高精度。
简述一下更相减损术的过程,对于a和b,若其中只有一个是偶数,说明他们两个的最大公因数一定不是偶数,没有2这个因子,所以将其中的偶数除以2;若全是偶数,说明他们的最大公因数一定是偶数,一定有2这个因子,全部除以2,再将最终答案乘以2;若全为奇数,则用大数减小数。不断重复,直到a和b相等,就是答案。
实际上,上面的算法严格意义上不是更相减损术,而是Stein算法,但二者都是通过减来求最大公约数,无非Stein算法多了只有一个数是偶数时的优化。
另外,把高精度写成结构体确实方便,不过很容易出事,嗯,至少这次,需要写乘2和除以2的函数,如果重载运算符的话,就会因为一些语言的原因而超时。
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <string> 5 6 using namespace std; 7 8 const int maxn = 1e4 + 5; 9 10 struct BigInteger { 11 int num[maxn], len; 12 13 BigInteger(string s = "") { 14 memset(num, 0, sizeof(num)); 15 len = s.length(); 16 for (int i = 1; i <= len; ++i) 17 num[i] = s[len - i] - '0'; 18 } 19 20 bool operator < (const BigInteger& rhs) const { 21 if (len != rhs.len) return len < rhs.len; 22 else { 23 for (int i = len; i >= 1; --i) 24 if (num[i] != rhs.num[i]) 25 return num[i] < rhs.num[i]; 26 } 27 return false; 28 } 29 30 bool operator == (const BigInteger& rhs) const { 31 return !(*this < rhs) && !(rhs < *this); 32 } 33 34 void operator - (const BigInteger& rhs) { 35 for (int i = 1; i <= len; ++i) { 36 num[i] -= rhs.num[i]; 37 if (num[i] < 0) --num[i + 1], num[i] += 10; 38 } 39 while (!num[len] && len > 1) --len; 40 } 41 42 void mul2() { 43 for (int i = 1; i <= len; ++i) 44 num[i] *= 2; 45 for (int i = 1; i <= len; ++i) { 46 int j = i; 47 while (num[j] > 9) { 48 num[j + 1] += num[j] / 10; 49 num[j++] %= 10; 50 } 51 } 52 if (num[len + 1]) ++len; 53 } 54 void div2() { 55 for (int i = len; i >= 1; --i) { 56 num[i - 1] += num[i] % 2 * 10; 57 num[i] /= 2; 58 } 59 while (!num[len] && len > 1) --len; 60 } 61 62 void print() { 63 for (int i = len; i >= 1; --i) 64 printf("%d", num[i]); 65 } 66 } a, b; 67 68 string sa, sb; 69 70 int main() { 71 long long ans = 0; 72 cin >> sa >> sb; 73 a = BigInteger(sa), b = BigInteger(sb); 74 while (!(a == b)) { 75 if (a < b) swap(a, b); 76 if (a.num[1] % 2 == 0 && b.num[1] % 2) 77 a.div2(); 78 else if (b.num[1] % 2 == 0 && a.num[1] % 2) 79 b.div2(); 80 else if (a.num[1] % 2 == 0 && b.num[1] % 2 == 0) { 81 a.div2(); 82 b.div2(); 83 ++ans; 84 } else a - b; 85 } 86 for (int i = 1; i <= ans; ++i) 87 a.mul2(); 88 a.print(); 89 return 0; 90 }