最大公约数
给定两个不超过10^3000位的正整数A,B
正文
/*
原题:T1627「一本通 6.3 例 3」最大公约数
题意:给定两个不超过 10^3000 位的正整数 A,B,输出它们的最大公约数。
思路:用压位大整数(基 1e9)存放大数,采用二进制 GCD(Stein 算法),仅用移位与减法,避免大数除法。
复杂度:时间 O(位数^2) / 空间 O(位数)
易错点:基非 2 的幂,右移/左移需按位借位与进位;减法要保证被减数不小于减数。
*/
#include <bits/stdc++.h>
using namespace std;
const long long BASE=1000000000;
struct Big{
vector<int> d; // 小端,d[0] 最低位,基 1e9
Big(){
d.push_back(0);
}
Big(const string& s){
int n=(int)s.size();
for(int i=n;i>0;i-=9){
int st=max(0, i-9);
d.push_back(stoi(s.substr(st, i-st)));
}
if(d.empty()) d.push_back(0);
normalize();
}
void normalize(){
while(d.size()>1 && d.back()==0) d.pop_back();
}
bool isZero() const{
return d.size()==1 && d[0]==0;
}
bool isEven() const{
return (d[0]&1)==0;
}
// 返回 -1/0/1
int cmp(const Big& o) const{
if(d.size()!=o.d.size()) return d.size()<o.d.size()?-1:1;
for(int i=(int)d.size()-1;i>=0;i--){
if(d[i]!=o.d[i]) return d[i]<o.d[i]?-1:1;
}
return 0;
}
// 除以 2(向下取整)
void shr1(){
long long carry=0;
for(int i=(int)d.size()-1;i>=0;i--){
long long cur=d[i]+carry*BASE;
d[i]=(int)(cur/2);
carry=cur%2;
}
normalize();
}
// 乘以 2
void shl1(){
long long carry=0;
for(int i=0;i<(int)d.size();i++){
long long cur=(long long)d[i]*2+carry;
d[i]=(int)(cur%BASE);
carry=cur/BASE;
}
if(carry) d.push_back((int)carry);
}
// 乘以 2^k
void shlk(int k){
for(int i=0;i<k;i++) shl1();
}
// *this -= o,要求 *this >= o
void subFrom(const Big& o){
int borrow=0;
for(int i=0;i<(int)d.size();i++){
long long x=d[i]-borrow;
if(i<(int)o.d.size()) x-=o.d[i];
if(x<0){
x+=BASE;
borrow=1;
}else{
borrow=0;
}
d[i]=(int)x;
}
normalize();
}
string toStr() const{
if(isZero()) return "0";
char buf[16];
sprintf(buf, "%d", d.back());
string res=buf;
for(int i=(int)d.size()-2;i>=0;i--){
sprintf(buf, "%09d", d[i]);
res+=buf;
}
return res;
}
};
Big bgcd(Big a, Big b){
if(a.isZero()) return b;
if(b.isZero()) return a;
int k=0;
while(a.isEven() && b.isEven()){
a.shr1();
b.shr1();
k++;
}
while(a.isEven()) a.shr1();
while(true){
while(b.isEven()) b.shr1();
if(b.cmp(a)<0) swap(a, b);
b.subFrom(a);
if(b.isZero()) break;
}
a.shlk(k);
return a;
}
int main(){
string A, B;
cin>>A>>B;
Big a(A), b(B);
Big g=bgcd(a, b);
cout<<g.toStr()<<"\n";
return 0;
}
一本通·提高篇的其它内容
- 活动安排
- 种树
- 喷水装置
- 加工生产调度
- 智力大冲浪
- 数列极差
- 数列分段
- 线段
- 家庭作业
- 钓鱼
- 糖果传递
- 愤怒的牛
- Best Cow Fences
- 曲线
- 数列分段 II
- 扩散
- 灯泡
- 传送带
- 数的划分
- 生日蛋糕
- 小木棍
- Addition Chains
- 埃及分数
- 平板涂色
- 质数方阵
- 靶形数独
- 电路维修
- 魔板
- Knight Moves
- 棋盘游戏
- Keyboarding
- 移动玩具
- 山峰和山谷
- Oulipo
- 图书管理
- Power Strings
- Seekthe Name, Seek the Fame
- Friends
- A Horrible Poem
- Beads
- Antisymmetry
- 门票
- 收集雪花
- 剪花布条
- Power Strings
- Radio Transmission
- OKR-Periods of Words
- 似乎在梦中见过的样子
- Censoring
- Phone List
- The XOR Largest Pair
- Nikitosh 和异或
- Immediate Decodability
- L 语言
- Secret Message 秘密信息
- 背单词
- The Xor-longest Path
- Keywords Search
- 玄武密码
- Censoring