【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 }
AC代码
原文地址:https://www.cnblogs.com/Mr94Kevin/p/9825103.html