P2152 [SDOI2009]SuperGCD
非常显du然liu的一道题
就是求GCD
因为数据范围...
所以要上压位高精+非递归的辗转相减
关于辗转相减:
如果 A是二的倍数,B是二的倍数 那么GCD(A,B)=2 * GCD(A,B)
如果只有A是二的倍数 那么GCD(A,B)=GCD(A/2,B)
如果只有B是二的倍数 那么GCD(A,B)=GCD(A,B/2)
十分显然的结论...
然后不停地让大的数减去小的数
最后当它们相等时就是GCD了(因为大的减小的一直减到不能减就相当于取模)
int slove() { int A=read(),B=read(),i=0,j=0; while(!(A&1)) A>>=1,i++; while(!(B&1)) B>>=1,j++; //先把A,B都除成奇数 //这样之后辗转相减时就不会出现两个数都是偶数的情况了 //可以减少判断次数 int cnt=min(i,j); while(233) { if(A<B) swap(A,B); if(A==B) return A<<cnt; A=A-B; while(!(A&1)) A>>=1; } }
然后就是恶心的压位高精了...
可以发现我们高精乘除都只乘除2,所以只要写高精乘2和高精除2以及高精减法就好了
重载运算符和压位都是基本操作了
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef long long ll; const ll wid=100000000; char ch[20007]; struct bigint { ll s[1257],len; bigint() { memset(s,0,sizeof(s)); len=0; } inline void read() { scanf("%s",ch+1); int l=strlen(ch+1),t=0,k=1; len=(l+7)/8; for(int i=l;i;i--) { if(!(l-i)%8){ k=1; t++; } s[t]+=k*(ch[i]^48); k*=10; } } inline void print() { if(!len) { printf("0\n"); return; } printf("%lld",s[len]); for(int i=len-1;i;i--) printf("%08lld",s[i]);//除了第一位不足的位用0补 printf("\n"); } inline bool operator < (const bigint &tmp) const { if(len!=tmp.len) return len<tmp.len; for(int i=tmp.len;i;i--) if(s[i]!=tmp.s[i]) return s[i]<tmp.s[i]; return 0; } inline bool operator == (const bigint &tmp) const { return !(tmp<*this)&&!(*this<tmp); } inline bigint operator - (const bigint &tmp) const { bigint u; u.len=len; for(int i=1;i<=len;i++) { u.s[i]+=s[i]-tmp.s[i]; if(u.s[i]<0) u.s[i]+=wid,u.s[i+1]--; } while(!u.s[u.len]&&u.len) u.len--; return u; } inline bool pd(){ return s[1]&1; }//判断奇偶 inline void div2()//除2 { len+=2; for(int i=len;i;i--) { if(s[i]&1) s[i-1]+=wid; s[i]>>=1; } while(!s[len]&&len) len--; } inline void mul2()//乘2 { for(int i=1;i<=len;i++) s[i]*=2; len+=2; for(int i=1;i<=len;i++) { s[i+1]+=s[i]/wid; s[i]%=wid; } while(!s[len]&&len) len--; } }a,b; void slove() { int i=0,j=0; while(!a.pd()) a.div2(),i++; while(!b.pd()) b.div2(),j++; if(i>j) i=j; while(1) { if(a<b) swap(a,b); if(a==b) break; a=a-b; while(!a.pd()) a.div2(); } for(int k=1;k<=i;k++) a.mul2(); a.print(); } int main() { a.read(); b.read(); slove(); return 0; }