一本通1627【例 3】最大公约数

1627:【例 3】最大公约数

时间限制: 1000 ms         内存限制: 524288 KB

【题目描述】

给出两个正整数 A,B,求它们的最大公约数。

【输入】

输入共两行,第一行一个正整数 A,第二行一个正整数 B。

【输出】

在第一行输出一个整数,表示 A,B 的最大公约数。

【输入样例】

18
24

【输出样例】

6

【提示】

数据范围与提示:

对于 60% 的数据,1≤A,B≤1018

对于 100% 的数据,1≤A,B≤103000 。

sol:Super Gcd,高精。。。

直接辗转相除肯定优秀到爆炸,所以我们选择辗转相减

然而直接辗转相减肯定也是优秀到爆炸,但是这道题特别水的数据居然让我过了,这还说什么。。。

对于辗转相减有一个优化,就是对于当前两个数,如果一奇一偶,就把偶数除以2,如果两个偶,就都除以2,把答案*2,如果两奇就辗转相减。

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=‘ ‘;
    while(!isdigit(ch))
    {
        f|=(ch==‘-‘); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar(‘-‘); x=-x;
    }
    if(x<10)
    {
        putchar(x+‘0‘);    return;
    }
    write(x/10);
    putchar((x%10)+‘0‘);
    return;
}
#define W(x) write(x),putchar(‘ ‘)
#define Wl(x) write(x),putchar(‘\n‘)
inline void Read_S(char *S)
{

    int Len=0;
    char ch=‘ ‘;
    while(!isdigit(ch))
    {
        ch=getchar();
    }
    while(ch==‘0‘)
    {
        ch=getchar();
    }
    while(isdigit(ch))
    {
        S[++Len]=ch; ch=getchar();
    }
    return;
}
const int N=3005;
const int Base=10000,Power=4;
char SX[N],SY[N];
struct BigNum
{
    int a[N];
    BigNum()
    {
        memset(a,0,sizeof a);
    }
    BigNum(char *S)
    {
        memset(a,0,sizeof a);
        int i,bb,Pos=0,Len=strlen(S+1);
        a[0]=(Len-1)/Power+1;
        for(i=1;i<=Len;i++)
        {
            if((i-1)%Power==0)
            {
                Pos++; bb=1;
            }
            a[Pos]+=bb*(S[i]-‘0‘);
            bb*=10;
        }
    }
    inline void Print()
    {
        write(a[a[0]]);
        int i;
        for(i=a[0]-1;i>=1;i--)
        {
            if(a[i]<1000) putchar(‘0‘);
            if(a[i]<100) putchar(‘0‘);
            if(a[i]<10) putchar(‘0‘);
            write(a[i]);
        }
    }
    #define P(x) x.Print(),putchar(‘ ‘)
    #define Pl(x) x.Print(),putchar(‘\n‘)
}X,Y;
inline bool operator<(const BigNum &p,const BigNum &q)
{
    if(p.a[0]!=q.a[0]) return p.a[0]<q.a[0];
    int i;
    for(i=p.a[0];i>=1;i--) if(p.a[i]!=q.a[i])
    {
        return p.a[i]<q.a[i];
    }
    return false;
}
inline bool operator==(const BigNum &p,const BigNum &q)
{
    if(p.a[0]!=q.a[0]) return false;
    int i;
    for(i=p.a[0];i>=1;i--) if(p.a[i]!=q.a[i])
    {
        return false;
    }
    return true;
}
inline BigNum operator-(const BigNum &p,const BigNum &q)
{
    int i;
    BigNum ans=p;
    for(i=1;i<=q.a[0];i++)
    {
        ans.a[i]-=q.a[i];
        if(ans.a[i]<0)
        {
            ans.a[i]+=Base;
            ans.a[i+1]--;
        }
    }
    while((!ans.a[ans.a[0]])&&ans.a[0]) ans.a[0]--;
    return ans;
}
int main()
{
    freopen("data.in","r",stdin);
    freopen("my.out","w",stdout);
    Read_S(SX);
    reverse(SX+1,SX+strlen(SX+1)+1);
    X=BigNum(SX);
    Read_S(SY);
    reverse(SY+1,SY+strlen(SY+1)+1);
    Y=BigNum(SY);
    while(!(X==Y))
    {
        BigNum p,q;
        if(X<Y)
        {
            p=Y;
            q=X;
        }
        else
        {
            p=X;
            q=Y;
        }
        X=q;
        Y=p-q;
    }
    Pl(X);
    return 0;
}

意外水过的辗转相减

#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=‘ ‘;
    while(!isdigit(ch))
    {
        f|=(ch==‘-‘); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar(‘-‘); x=-x;
    }
    if(x<10)
    {
        putchar(x+‘0‘);    return;
    }
    write(x/10);
    putchar((x%10)+‘0‘);
    return;
}
#define W(x) write(x),putchar(‘ ‘)
#define Wl(x) write(x),putchar(‘\n‘)
inline void Read_S(char *S)
{

    int Len=0;
    char ch=‘ ‘;
    while(!isdigit(ch))
    {
        ch=getchar();
    }
    while(ch==‘0‘)
    {
        ch=getchar();
    }
    while(isdigit(ch))
    {
        S[++Len]=ch; ch=getchar();
    }
    return;
}
const int N=3005;
const int Base=10000,Power=4;
char SX[N],SY[N];
struct BigNum
{
    int a[N];
    BigNum()
    {
        memset(a,0,sizeof a);
    }
    BigNum(char *S)
    {
        memset(a,0,sizeof a);
        int i,bb,Pos=0,Len=strlen(S+1);
        a[0]=(Len-1)/Power+1;
        for(i=1;i<=Len;i++)
        {
            if((i-1)%Power==0)
            {
                Pos++; bb=1;
            }
            a[Pos]+=bb*(S[i]-‘0‘);
            bb*=10;
        }
    }
    inline void Print()
    {
        write(a[a[0]]);
        int i;
        for(i=a[0]-1;i>=1;i--)
        {
            if(a[i]<1000) putchar(‘0‘);
            if(a[i]<100) putchar(‘0‘);
            if(a[i]<10) putchar(‘0‘);
            write(a[i]);
        }
    }
    #define P(x) x.Print(),putchar(‘ ‘)
    #define Pl(x) x.Print(),putchar(‘\n‘)
}X,Y,Ans;
inline bool operator<(const BigNum &p,const BigNum &q)
{
    if(p.a[0]!=q.a[0]) return p.a[0]<q.a[0];
    int i;
    for(i=p.a[0];i>=1;i--) if(p.a[i]!=q.a[i])
    {
        return p.a[i]<q.a[i];
    }
    return false;
}
inline bool operator==(const BigNum &p,const BigNum &q)
{
    if(p.a[0]!=q.a[0]) return false;
    int i;
    for(i=p.a[0];i>=1;i--) if(p.a[i]!=q.a[i])
    {
        return false;
    }
    return true;
}
inline BigNum operator-(const BigNum &p,const BigNum &q)
{
    int i;
    BigNum ans=p;
    for(i=1;i<=q.a[0];i++)
    {
        ans.a[i]-=q.a[i];
        if(ans.a[i]<0)
        {
            ans.a[i]+=Base;
            ans.a[i+1]--;
        }
    }
    while((!ans.a[ans.a[0]])&&ans.a[0]) ans.a[0]--;
    return ans;
}
inline BigNum operator*(const BigNum &p,const BigNum &q)
{
    int i,j;
    BigNum ans; ans.a[0]=max(p.a[0],q.a[0]);
    for(i=1;i<=p.a[0];i++)
    {
        for(j=1;j<=q.a[0];j++)
        {
            ans.a[i+j-1]+=p.a[i]*q.a[j];
            ans.a[i+j]+=ans.a[i+j-1]/Base;
            ans.a[i+j-1]%=Base;
        }
    }
    while(ans.a[ans.a[0]+1]) ans.a[0]++;
    while(!ans.a[ans.a[0]]) ans.a[0]--;
    return ans;
}
inline bool Judge_Ou(BigNum p)
{
    if(!p.a[0]) return 1;
    return (p.a[1]&1)?0:1;
}
inline BigNum Div2(BigNum p)
{
    BigNum ans;
    ans.a[0]=p.a[0];
    int i;
    for(i=p.a[0];i>=1;i--)
    {
        ans.a[i]+=(p.a[i]>>1);
        if(p.a[i]&1) p.a[i-1]+=Base;
    }
    while(!ans.a[ans.a[0]]) ans.a[0]--;
    return ans;
}
inline BigNum Mul2(BigNum p)
{
    BigNum ans;
    ans.a[0]=p.a[0];
    int i;
    for(i=1;i<=p.a[0];i++)
    {
        p.a[i]<<=1;
        if(p.a[i]>Base)
        {
            ans.a[i+1]+=p.a[i]/Base;
            p.a[i]%=Base;
        }
        ans.a[i]+=p.a[i];
    }
    while(ans.a[ans.a[0]+1]) ans.a[0]++;
    return ans;
}
int main()
{
    freopen("data.in","r",stdin);
    freopen("my.out","w",stdout);
    Read_S(SX);
    reverse(SX+1,SX+strlen(SX+1)+1);
    X=BigNum(SX);
    Read_S(SY);
    reverse(SY+1,SY+strlen(SY+1)+1);
    Y=BigNum(SY);
    Ans.a[0]=Ans.a[1]=1;
    while(!(X==Y))
    {
//        P(X); Pl(Y);
        bool BoX=Judge_Ou(X),BoY=Judge_Ou(Y);
        if(BoX)
        {
            if(BoY)
            {
                X=Div2(X); Y=Div2(Y); Ans=Mul2(Ans);
            }
            else
            {
                X=Div2(X);
            }
        }
        else
        {
            if(BoY)
            {
                Y=Div2(Y);
            }
            else
            {
                BigNum p,q;
                if(X<Y) p=Y,q=X;
                else p=X,q=Y;
                X=p-q; Y=q;
            }
        }
    }
    Ans=Ans*X;
    Pl(Ans);
    return 0;
}

带优化的正确姿势

原文地址:https://www.cnblogs.com/gaojunonly1/p/10433546.html

时间: 2024-10-01 13:30:17

一本通1627【例 3】最大公约数的相关文章

最大公约数(信息学奥赛一本通 1627)

[题目描述] 给出两个正整数 A,B,求它们的最大公约数. [输入] 输入共两行,第一行一个正整数 A,第二行一个正整数 B. [输出] 在第一行输出一个整数,表示 A,B 的最大公约数. [输入样例] 18 24 [输出样例] 6 [提示] 数据范围与提示: 对于 60% 的数据,1≤A,B≤1018: 对于 100% 的数据,1≤A,B≤103000 . 首先看到这道题的数据范围之后,我们肯定是得用高精度呐,然后为了方便一点,缩小数组大小,我们还可以引进“压位高精度”,一般来说,最好使用四位

C语言程序设计100例之(10):最大公约数

例10        最大公约数 问题描述 有三个正整数a,b,c(0<a,b,c<10^6),其中c不等于b.若a和c的最大公约数为b,现已知a和b,求满足条件的最小的c. 输入数据 第一行输入一个n,表示有n组测试数据,接下来的n行,每行输入两个正整数a,b. 输出格式 输出对应的c,每组测试数据占一行. 输入样例 2 6 2 12 4 输出样例 4 8 (1)编程思路. 利用转辗相除法求两个整数的最大公约数.例如,求整数m=48,n=18两个数的最大公约数的方法如左图所示. 具体做法是:

搜索入门练习题3 全组合 题解

题目出处:<信息学奥赛一本通>例5.2. 题目描述 设有 \(n\) 个数的集合 \(\{1,2,...,n\}\) ,从中任意取出 \(r\) 个数进行排列 \((r \le n)\) ,试列出所有的排列. 输入格式 输入包含两个正数 \(n,r(1 \le r \le n \le 10)\) 输出格式 输出从 \(n\) 个数的集合中选出 \(r\) 个数的所有组合,每个组合方案占一行.对于每个组合,按照从小到大的顺序输出组合中的所有元素,两两之间有一个空格分隔. 样例输入 3 2 样例输

搜索入门练习题1 素数环 题解

题目出处:<信息学奥赛一本通>例5.1. 题目描述 素数环:从 \(1\) 到 \(n(2 \le n \le 20)\) 这 \(n\) 个数摆成一个环,要求相邻的两个数的和是一个素数. 输入格式 输入包含一个整数 \(n(2 \le n \le 20)\) . 输出格式 按字典序从小到大的顺序输出所有排列方案,每个排列方案占一行.每行的 \(n\) 个数之间由一个空格分隔. 样例输入 2 样例输出 1 2 2 1 问题分析 很明显,这是一道可以用搜索解决的问题,我们可以采用"回溯

搜索入门练习题5 八皇后问题 题解

题目来源:<信息学奥赛一本通>例5.4 题目描述 要在国际象棋棋盘(\(8 \times 8\) 的棋盘)中放 \(8\) 个皇后,使任意两个皇后都不能互相吃.(提示:皇后能吃同一行.同一列.同一对角线的任意棋子.) 输出格式 输出一个整数,用于表示八皇后问题的放置方案. 题目分析 首先我们用 \((x,y)\) 来表示棋盘上第 \(x\) 行第 \(y\) 列的格子的坐标. 那么,两个皇后 \((x_1,y_1)\) 和 \((x_2,y_2)\) 会互相攻击当且仅当满足如下条件之一: 在同

搜索入门练习题7 最高效益和 题解

题目出处:<信息学奥赛一本通>例5.6 题目描述 设有A.B.C.D.E五人从事J1.J2.J3.J4.J5五项工作,每人只能从事一项,他们的效益如下所示. ? J1 J2 J3 J4 J5 A 13 11 10 4 7 B 13 10 10 8 5 C 5 9 7 7 4 D 15 12 10 11 5 E 10 11 8 8 4 每人选择五项工作中的一项,在各种选择的组合中,找到效益最高的一组输出. 题目分析 这道题目其实就是"全排列"问题的变形题,我们可以使用深度优先

c语言(北京理工大学mooc 下)

求最大公约数和最小公倍数 题目内容: 编写程序,在主函数中输入两个正整数 a,b,调用两个函数 fun1() 和 fun2(),分别求 a 和 b 的最大公约数和最小公倍数,在主函数中输出结果. 输入格式: 两个正整数 输出格式: 最大公约数和最小公倍数 输入样例: 12,40[回车] 输出样例: 最大公约数:4[回车] 最小公倍数:120[回车] 1 #include<stdio.h> 2 #include<stdlib.h> 3 4 int LCM(int x, int y);

10249「一本通 1.3 例 5」weight

#10249「一本通 1.3 例 5」weight 题目描述 原题来自:USACO 已知原数列a1,a2,...,an中的前1项,前2项,前3项,... ,前 n 项的和,以及后 1 项,后 2 项,后 3 项,...,后 n 项的和,但是==所有的数都被打乱了顺序==.此外,我们还知道数列中的数存在于集合 S 中.试求原数列.当存在多组可能的数列时,求字典序最小的数列. 输入格式 第 1 行,一个整数 n . 第 2 行, 2 × n 个整数,注意:数据已被打乱. 第 3 行,一个整数 m ,

一本通1626【例 2】Hankson 的趣味题

1626:[例 2]Hankson 的趣味题 题目描述 Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson.现在,刚刚放学回家的Hankson 正在思考一个有趣的问题.今天在课堂上,老师讲解了如何求两个正整数c1 和c2 的最大公约数和最小公倍数.现在Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a0,a1,b0,b1,设某未知正整数x 满足:1.x 和a