• BZOJ1876 [SDOI2009]SuperGCD 【高精 + GCD优化】


    题目

    Sheng bill有着惊人的心算能力,甚至能用大脑计算出两个巨大的数的GCD(最大公约 数)!因此他经常和别人比
    赛计算GCD。有一天Sheng bill很嚣张地找到了你,并要求和你比 赛,但是输给Sheng bill岂不是很丢脸!所以你
    决定写一个程序来教训他。

    输入格式

    共两行: 第一行:一个数A。 第二行:一个数B。
    0 < A , B ≤ 10 ^ 10000。

    输出格式

    一行,表示A和B的最大公约数。

    输入样例

    12

    54

    输出样例

    6

    题解

    时隔大半年,我回来A这道题啦【当初写的太BUG了】
    求GCD,很容一想到辗转相除,而高精不好操作取模,这就用到了辗转相除法的本质:更相减损法

    GCD(a,b) = GCD(a,a-b) 【a >b】

    然而这样会T,所以我们还要优化:

    GCD(a,b) = 2*GCD(a/2,b/2) 【2|a且2|b】
    GCD(a,b) = GCD(a/2,b) 【2|a】
    GCD(a,b) = GCD(a,b/2) 【2|b】
    GCD(a,b) = GCD(a,a-b) 【a >b】
    加上个压位高精【高精减法,高精除低精,高精乘低精,高精比较】
    就可以A了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    using namespace std;
    const int maxn = 10005,B = 4,Base = 10000,maxm = 100005,INF = 1000000000;
    struct NUM{
        int s[maxn],len;
        NUM() {memset(s,0,sizeof(s)); len = 0;}
    };
    istream& operator >>(istream& in,NUM& a){
        string s;
        in>>s;
        int temp = 0,t = 1;
        for (int i = s.length() - 1; i >= 0; i--){
            temp = temp + t * (s[i] - '0');
            if (t * 10 == Base) a.s[++a.len] = temp,temp = 0,t = 1;
            else t *= 10;
        }
        if (temp) a.s[++a.len] = temp;
        return in;
    }
    ostream& operator <<(ostream& out,const NUM& a){
        if (!a.len) out<<0;
        else {
            printf("%d",a.s[a.len]);
            for (int i = a.len - 1; i > 0; i--) printf("%04d",a.s[i]);
        }
        return out;
    }
    bool check(const NUM& a){return !(a.s[1] & 1);}
    bool equal(const NUM& a,const NUM& b){
        if (a.len != b.len) return false;
        REP(i,a.len) if (a.s[i] != b.s[i]) return false;
        return true;
    }
    bool operator <(const NUM& a,const NUM& b){
        if (a.len < b.len) return true;
        if (a.len > b.len) return false;
        for (int i = a.len; i > 0; i--){
            if (a.s[i] < b.s[i]) return true;
            if (a.s[i] > b.s[i]) return false;
        }
        return false;
    }
    void Half(NUM& a){
        int carry = 0,temp;
        for (int i = a.len; i > 0; i--){
            temp = (a.s[i] + carry * Base) / 2;
            carry = a.s[i] + carry * Base - temp * 2;
            a.s[i] = temp;
        }
        while (!a.s[a.len]) a.len--;
    }
    void Twice(NUM& a){
        int carry = 0,temp;
        for (int i = 1; i <= a.len; i++){
            temp = a.s[i] * 2 + carry;
            a.s[i] = temp % Base;
            carry = temp / Base;
        }
        while (carry) a.s[++a.len] = carry % Base,carry /= Base;
    }
    NUM operator -(const NUM& a,const NUM& b){
        NUM c; c.len = a.len;
        int carry = 0,temp;
        for (int i = 1; i <= a.len; i++){
            temp = a.s[i] - b.s[i] + carry;
            if (temp < 0) carry = -1,temp += Base;
            else carry = 0;
            c.s[i] = temp;
        }
        while (!c.s[c.len]) c.len--;
        return c;
    }
    int main(){
        NUM A,B; int cnt = 0;
        cin>>A>>B;
        while (!equal(A,B)){
            if (check(A) && check(B)) Half(A),Half(B),cnt++;
            else if (check(A)) Half(A);
            else if (check(B)) Half(B);
            else {
                if (B < A) swap(A,B);
                B = B - A;
            }
        }
        while (cnt--) Twice(A);
        cout<<A<<endl;
        return 0;
    }
    
  • 相关阅读:
    Logging with PSR-3 to Improve Reusability
    php -- 取路径:getcwd()、__DIR__、__FILE__ 的区别
    默认网关和默认路由 —— Cisco CCNA – Default Gateway & Default Routes
    nginx rewrite only specific servername to https
    c语言中pthread的理解和使用
    socket bind 随机端口
    【转】php里面也可以使用协程
    【转】十个经典的C开源项目代码
    主机无法访问虚拟机上的elasticsearch服务器
    Ubuntu: an error occurred while mounting /mnt/hgfs
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282745.html
Copyright © 2020-2023  润新知