「BZOJ 1876」「SDOI 2009」SuperGCD「数论」

题意

\(\gcd(a, b)\),其中\(a,b\leq10^{10000}\)

题解

使用\(\text{Stein}\)算法,其原理是不断筛除因子\(2\)然后使用更相减损法

如果不筛\(2\)因子的话复杂度是线性的,比如\(a=1,b=10^{10000}\)

再证明下更相减损术,即\(\gcd(a,b)=gcd(a-b,b)\)

假设\(d=\gcd(a,b)\),则\(a=pd,b=qd\)

根据定义可知\(\gcd(p,q)=1\)

因此\(px+qy=1\)存在解\(x,y\)

此时\(a-b=pd-q-d=(p-q)d,b=qd\)

\((p-q)x+q(x+y)=px+qy=1\)

得到\(\gcd(p-q,q)=1\),根据定义得到\(d=\gcd(a-b,b)\)

注意一下高精要压位,不然常数巨大

#include <algorithm>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;

const int base = 1e9;
const int N = 1e4 + 10;

struct Int {
    int len, n[N / 9 + 10];
    Int() {}
    Int(char * s) {
        int x = strlen(s);
        len = x / 9 + (x % 9 ? 1 : 0);
        int p = x - 1;
        for(int i = 1; i <= len; i ++) {
            n[i] = 0;
            for(int j = min(p, 8); j >= 0; j --)
                n[i] = n[i] * 10 + (s[p - j] & 15);
            p -= 9;
        }
    }
    bool zero() { return len == 1 && n[1] == 0; }
    bool judge() { return !zero() && 0 == (n[1] & 1); }
    bool operator < (const Int &b) const {
        if(len != b.len) return len < b.len;
        for(int i = len; i >= 1; i --)
            if(n[i] != b.n[i]) return n[i] < b.n[i];
        return 0;
    }
    bool operator -= (const Int &b) {
        for(int i = 1; i <= len; i ++) {
            if(i <= b.len) {
                n[i] -= b.n[i];
                if(n[i] < 0) n[i + 1] --, n[i] += base;
            }
        }
        for(; !n[len] && len > 1; len --);
        return zero();
    }
    void div2() {
        for(int i = 1; i <= len; i ++) {
            if(n[i] & 1) n[i - 1] += base >> 1;
            n[i] >>= 1;
        }
        for(; !n[len] && len > 1; len --);
    }
    void operator <<= (const int &x) {
        for(int t = 1; t <= x; t ++) {
            n[len + 1] = 0;
            for(int i = len; i >= 1; i --) {
                n[i] <<= 1; n[i + 1] += n[i] / base; n[i] %= base;
            }
            if(n[len + 1]) len ++;
        }
        this -> print();
    }
    void print() {
        for(int i = len; i >= 1; i --)
            if(i == len) printf("%d", n[i]);
            else printf("%09d", n[i]);
        printf("\n");
    }
} x, y;

int main() {
    static char A[N], B[N];
    scanf("%s %s", A, B);
    x = Int(A), y = Int(B);
    if(x.zero()) return y.print(), 0;
    if(y.zero()) return x.print(), 0;
    int i = 0, j = 0;
    for(; x.judge(); i ++) x.div2();
    for(; y.judge(); j ++) y.div2();
    while(1) {
        if(!(x < y)) {
            if(x -= y) return y <<= min(i, j), 0;
            while(x.judge()) x.div2();
        } else {
            if(y -= x) return x <<= min(i, j), 0;
            while(y.judge()) y.div2();
        }
    }
    return 0;
}

posted @ 2019-02-13 21:05  hfhongzy  阅读(234)  评论(0编辑  收藏  举报