[SDOI2009]SuperGCD
Description
Sheng bill有着惊人的心算能力,甚至能用大脑计算出两个巨大的数的GCD(最大公约 数)!因此他经常和别人比赛计算GCD。有一天Sheng bill很嚣张地找到了你,并要求和你比 赛,但是输给Sheng bill岂不是很丢脸!所以你决定写一个程序来教训他。
Input
共两行: 第一行:一个数A。 第二行:一个数B。
0 < A , B ≤ 10 ^ 10000。
Output
一行,表示A和B的最大公约数。
Sample Input
12
54
Sample Output
6
写个高精度取模,这题就没了。。。
其实没比要写高精度取模,其实辗转相除法的前身是更相减损术,具体可以去百度或Google
流程如下:
- 给定两个数A,B,令A>B
- 若A,B都能被2整除,则让A和B都除2,将答案乘2,并重复执行步骤2
- 若A能被2整除,则让A除2,直至不能被2整除
- 若B能被2整除,则让B除2,直至不能被2整除
- 若A,B相等,则将答案乘上A,并且退出,否则执行步骤6
- 令A=A-B,若此时A<B,则交换A,B,并且执行步骤2
初始时将答案设为1
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
int x=0,f=1; char ch=gc();
for (;ch<'0'||ch>'9';ch=gc()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline int read(){
int x=0,f=1; char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
return x*f;
}
inline void print(int x){
if (x<0) putchar('-'),x=-x;
if (x>9) print(x/10);
putchar(x%10+'0');
}
const int digit=8;
const int base=1e8;
const int maxn=1.3e3;
char s[maxn*digit];
struct Bignum{
int v[maxn],len;
Bignum(){memset(v,0,sizeof(v)),len=1;}
void init(){v[0]=1;}
void read(){
char ch=gc(); int t=0,tim=1;
for (;ch<'0'||ch>'9';ch=gc());
for (;ch>='0'&&ch<='9';ch=gc()) s[t++]=ch;
len=(t-1)/digit+1;
for (int i=0,j=t-1;i<j;i++,j--) swap(s[i],s[j]);
for (int i=0;i<t;i++){
v[i/digit]+=tim*(s[i]-'0'),tim*=10;
if (tim==base) tim=1;
}
}
void write(){
printf("%d",v[len-1]);
for (int i=len-2;~i;i--) printf("%0*d",digit,v[i]);
putchar('\n');
}
}A,B;
Bignum operator -(const Bignum &x,const Bignum &y){
Bignum z;
z.len=max(x.len,y.len);
for (int i=0;i<=z.len;i++){
z.v[i]+=x.v[i]-y.v[i];
if (z.v[i]<0) z.v[i]+=base,z.v[i+1]--;
}
while (!z.v[z.len]&&z.len>1) z.len--;
while (z.v[z.len]) z.v[z.len+1]+=z.v[z.len]/base,z.v[z.len]%=base,z.len++;
return z;
}
Bignum operator *(const Bignum &x,int y){
Bignum z;
z.len=x.len;
for (int i=0;i<=x.len;i++) z.v[i]+=x.v[i]*y,z.v[i+1]+=z.v[i]/base,z.v[i]%=base;
while (z.v[z.len]) z.v[z.len+1]+=z.v[z.len]/base,z.v[z.len]%=base,z.len++;
return z;
}
Bignum operator /(const Bignum &x,int y){
Bignum z; z=x;
for (int i=z.len;i;i--) z.v[i-1]+=z.v[i]%y*base,z.v[i]/=y; z.v[0]/=y;
while (!z.v[z.len]&&z.len>1) z.len--;
while (z.v[z.len]) z.v[z.len+1]+=z.v[z.len]/base,z.v[z.len]%=base,z.len++;
return z;
}
bool operator <(const Bignum &x,const Bignum &y){
if (x.len!=y.len) return x.len<y.len;
for (int i=x.len;~i;i--) if (x.v[i]!=y.v[i]) return x.v[i]<y.v[i];
return 1;
}
bool operator ==(const Bignum &x,const Bignum &y){
if (x.len!=y.len) return 0;
for (int i=0;i<=x.len;i++) if (x.v[i]!=y.v[i]) return 0;
return 1;
}
int main(){
A.read(),B.read();
if (A<B) swap(A,B);
int num=0;
while (true){
int cntA=0,cntB=0;
while (A.v[0]%2==0) A=A/2,cntA++;
while (B.v[0]%2==0) B=B/2,cntB++;
num+=min(cntA,cntB);
if (A==B) break;
if (A<B) swap(A,B);
A=A-B;
}
for (int i=1;i<=num;i++) A=A*2;
A.write();
}