洛谷题单指南-进阶数论-P2152 [SDOI2009] SuperGCD
原题链接:https://www.luogu.com.cn/problem/P2152
题意解读:求两个大数的最大公约数
解题思路:
大数不便于做除法取模,因此辗转相除法不合适。
但是高精度减法可行,考虑更相减损术!
1、更相减损术
如果a>=b,gcd(a,b) = gcd(a-b, b)
2、优化版
直接使用原始的更相减损术时间时间复杂度为O(n)
如果a、b都是偶数,那么gcd(a, b) = 2 * gcd(a / 2, b / 2)
如果a、b有一个是偶数,假设a是偶数,那么gcd(a, b) = gcd(a / 2, b)
由于当a、b有一个是偶数时,每次递归可以将数减半,而两个都是奇数时,a-b则一定是偶数,下次还是会减半
因此这样一来gcd整体递归的次数可以认为是O(logn)
100分代码:
#include <bits/stdc++.h>
using namespace std;
vector<int> a, b, result;
int cmp(vector<int> &a, vector<int> &b) // 比较两个大数的大小
{
if(a.size() != b.size()) return a.size() > b.size() ? 1 : -1;
for(int i = a.size() - 1; i >= 0; i--)
{
if(a[i] != b[i]) return a[i] > b[i] ? 1 : -1;
}
return 0; // 相等
}
vector<int> sub(vector<int> &a, vector<int> &b) // a - b
{
result.clear();
int t = 0; // 进位
for(int i = 0; i < a.size(); i++)
{
t = a[i] - t;
if(i < b.size()) t -= b[i];
result.push_back((t + 10) % 10);
if(t < 0) t = 1;
else t = 0;
}
while(result.size() > 1 && result.back() == 0) result.pop_back();
return result;
}
vector<int> div2(vector<int> &a) // 大数除以2
{
result.clear();
int t = 0; // 余数
for(int i = a.size() - 1; i >= 0; i--)
{
t = t * 10 + a[i];
result.push_back(t / 2);
t %= 2;
}
reverse(result.begin(), result.end());
while(result.size() > 1 && result.back() == 0) result.pop_back();
return result;
}
vector<int> mul(vector<int> &a, int b) // 大数乘以一个int型整数
{
result.clear();
int t = 0; // 进位
for(int i = 0; i < a.size(); i++)
{
t += a[i] * b;
result.push_back(t % 10);
t /= 10;
}
while(t)
{
result.push_back(t % 10);
t /= 10;
}
return result;
}
vector<int> supergcd(vector<int> &a, vector<int> &b)
{
if(cmp(a, b) == 0) return a;
if(a[0] % 2 == 0 && b[0] % 2 == 0)
{
a = div2(a);
b = div2(b);
a = supergcd(a, b); // 复用a,减少空间
return mul(a, 2);
}
else if(a[0] % 2 == 0 || b[0] % 2 == 0)
{
if(a[0] % 2 == 0) a = div2(a);
if(b[0] % 2 == 0) b = div2(b);
return supergcd(a, b);
}
else
{
if(cmp(a, b) < 0) swap(a, b);
a = sub(a, b); // 复用a,减少空间
return supergcd(a, b);
}
}
int main()
{
string sa, sb;
cin >> sa >> sb;
for(int i = sa.size() - 1; i >= 0; i--) a.push_back(sa[i] - '0');
for(int i = sb.size() - 1; i >= 0; i--) b.push_back(sb[i] - '0');
vector<int> ans = supergcd(a, b);
for(int i = ans.size() - 1; i >= 0; i--) cout << ans[i];
return 0;
}
浙公网安备 33010602011771号