P2152 [SDOI2009]SuperGCD

传送门

非常显duliu的一道题

就是求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;
}

 

posted @ 2018-10-12 15:56  LLTYYC  阅读(241)  评论(0编辑  收藏  举报