1 条题解
-
0
60分方法:
#include <bits/stdc++.h> using namespace std; /* 题意:求两个超大整数(位数可达 3000)的最大公约数。 * 做法:使用“欧几里得算法(辗转相除)”——但需要自己实现“大整数取模”。 * * 关键点: * 1) 将 A、B 作为十进制字符串读入; * 2) 实现 string 版本的:去前导零、比较、减法、与“单个数字相乘”; * 3) 用“按位长除法”实现 (a % b):依次把被除数的每一位“放下”, * 对当前余数 rem 与除数 b,二分查找一位商 q∈[0..9],使 b*q ≤ rem < b*(q+1), * 然后 rem -= b*q。最终的 rem 即为 a%b。 * 4) 在欧几里得算法中反复做取模,直到余数为 0。 * * 复杂度:设位数为 N,单次取模为 O(N^2) 左右;本题只有两数,足够通过。 */ /* ---------- 工具函数:字符串大整数基础运算 ---------- */ // 去掉前导零,保证“0”表示为单个字符 '0' static inline string trim_leading_zeros(const string &s) { size_t p = 0; while (p < s.size() && s[p] == '0') ++p; if (p == s.size()) return "0"; return s.substr(p); } // 比较两个“无前导零”的非负整数字符串:返回 -1/0/1 static inline int cmp_nonneg(const string &a, const string &b) { if (a.size() != b.size()) return (a.size() < b.size()) ? -1 : 1; if (a == b) return 0; return (a < b) ? -1 : 1; // 字典序比较在等长时等价于数值比较 } // 计算 a - b,要求 a >= b,均为“无前导零”的非负整数字符串 static string sub_nonneg(string a, const string &b) { // 从末位开始逐位相减 int i = (int)a.size() - 1; int j = (int)b.size() - 1; int borrow = 0; while (j >= 0 || borrow) { int x = a[i] - '0' - borrow; int y = (j >= 0 ? b[j] - '0' : 0); if (x < y) { x += 10; borrow = 1; } else borrow = 0; a[i] = char('0' + (x - y)); --i; --j; } // 前面剩余位不变,但可能产生前导零 return trim_leading_zeros(a); } // 计算 a * d,其中 0 <= d <= 9,a 为“无前导零”的非负整数字符串 static string mul_digit(const string &a, int d) { if (d == 0 || a == "0") return "0"; int carry = 0; string res; res.resize(a.size()); for (int i = (int)a.size() - 1; i >= 0; --i) { int t = (a[i] - '0') * d + carry; res[i] = char('0' + (t % 10)); carry = t / 10; } if (carry) res.insert(res.begin(), char('0' + carry)); return res; } /* ---------- 大整数取模:a % b(均为十进制非负整数字符串,b != "0") ---------- */ static string big_mod(string a, string b) { a = trim_leading_zeros(a); b = trim_leading_zeros(b); // 若 a < b,直接返回 a if (cmp_nonneg(a, b) < 0) return a; // b == 1 则直接 0 if (b == "1") return "0"; string rem = "0"; // 当前余数 rem.reserve(b.size() + 1); for (char ch : a) { // rem = rem * 10 + (ch - '0') if (rem == "0") rem = string(1, ch); // 避免形成前导零 else rem.push_back(ch); // 在 0..9 中二分出最大 q,使得 b*q <= rem int low = 0, high = 9, q = 0; while (low <= high) { int mid = (low + high) >> 1; string prod = mul_digit(b, mid); int r = cmp_nonneg(prod, rem); if (r <= 0) { q = mid; low = mid + 1; } else high = mid - 1; } if (q > 0) { string prod = mul_digit(b, q); rem = sub_nonneg(rem, prod); } // 若 q==0,rem 不变(仍然 < b),继续“放下”下一位 } return trim_leading_zeros(rem); } /* ---------- 主流程:大整数 GCD(欧几里得算法) ---------- */ int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string A, B; if (!(cin >> A)) return 0; cin >> B; A = trim_leading_zeros(A); B = trim_leading_zeros(B); // 欧几里得算法:gcd(a, b) = gcd(b, a % b),直到 b == 0 while (B != "0") { string R = big_mod(A, B); A = B; B = trim_leading_zeros(R); } cout << A << '\n'; return 0; }
- 1
信息
- ID
- 1083
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者