bzoj1876 [SDOI2009]SuperGCD

1876: [SDOI2009]SuperGCD

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 3744  Solved: 1349
[Submit][Status][Discuss]

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

HINT

 

Source

分析:这道题是一道非常烦人的高精度问题,求gcd谁都会,但是直接用欧几里得算法,高精度取模直接gg,而且还是压位的,打出来估计要半天.那么换一种方法:更相减损术:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。        ----摘自百度百科
也就是说我们只需要设计乘法,除法和减法就可以了。高精度算法就相当于模拟我们算术一样,只不过用程序跑而已,步骤是先操作,再进位、补位,最后看数组的长度有没有改变.
这道题一定要压位来处理,不然会tle,压位后的操作与没有压位差不多,只不过mod的数变了,以前是逢10进1,现在是逢n进1.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<map>

using namespace std;

const int mod = 100000000;

int tot;

struct node
{
    int x[2010], len;
}a,b;

void read(node &c)
{
    char s[10010];
    scanf("%s", s);
    int len = strlen(s),cnt = 0,chengji = 1;
    for (int i = len - 1; i >= 0; i--)
    {
        cnt = cnt + (s[i] - '0')* chengji;
        chengji *= 10;
        if ((len - i) % 8 == 0)
        {
            c.x[++c.len] = cnt;
            cnt = 0;
            chengji = 1;
        }
    }
    if (cnt != 0)
        c.x[++c.len] = cnt;
}

void div1()
{
    for (int i = a.len; i >= 1; i--)
    {
        if (a.x[i] % 2 == 1)
            a.x[i - 1] += mod;
        a.x[i] >>= 1;
    }
    while (a.x[a.len] == 0 && a.len > 1)
        a.len--;
}

void div2()
{
    for (int i = b.len; i >= 1; i--)
    {
        if (b.x[i] % 2 == 1)
            b.x[i - 1] += mod;
        b.x[i] >>= 1;
    }
    while (b.x[b.len] == 0 && b.len > 1)
        b.len--;
}

bool check()
{
    if (a.len != b.len)
        return false;
    for (int i = 1; i <= a.len; i++)
        if (a.x[i] != b.x[i])
            return false;
    return true;
}

bool cmp()
{
    if (a.len > b.len)
        return true;
    else
        if (a.len < b.len)
            return false;
    for (int i = a.len; i >= 1; i--)
    {
        if (a.x[i] > b.x[i])
            return true;
        else
            if (a.x[i] < b.x[i])
                return false;
    }
    return true;
}

void jian(node &c, node d)
{
    for (int i = 1; i <= c.len; i++)
    {
        if (c.x[i] >= d.x[i])
            c.x[i] -= d.x[i];
        else
        {
            c.x[i] = c.x[i] + mod - d.x[i];
            c.x[i + 1]--;
        }
    }
    while (c.x[c.len] == 0 && c.len > 1)
        c.len--;
}

void mul()
{
    for (int i = 1; i <= a.len; i++)
        a.x[i] <<= 1;
    for (int i = 1; i <= a.len; i++)
        if (a.x[i] >= mod)
        {
        a.x[i] -= mod;
        a.x[i + 1]++;
        }
    while (a.x[a.len + 1])
        a.len++;
}

void print()
{
    printf("%d", a.x[a.len]);
    for (int i = a.len - 1; i >= 1; i--)
        printf("%08d", a.x[i]);
    printf("\n");
}

int main()
{
    read(a);
    read(b);
    while (a.x[1] % 2 == 0 && b.x[1] % 2 == 0)
    {
        tot++;
        div1();
        div2();
    }
    while (!check())
    {
        if (cmp())
            jian(a, b);
        else
            jian(b, a);
        while (a.x[1] % 2 == 0)
            div1();
        while (b.x[1] % 2 == 0)
            div2();
    }
    while (tot--)
        mul();
    print();

    return 0;
}

 

 
posted @ 2017-08-19 16:29  zbtrs  阅读(381)  评论(0编辑  收藏  举报