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

【题目描述】

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

【输入】

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

【输出】

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

【输入样例】

18
24

【输出样例】

6

【提示】

数据范围与提示:

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

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


首先看到这道题的数据范围之后,我们肯定是得用高精度呐,然后为了方便一点,缩小数组大小,我们还可以引进“压位高精度”,一般来说,最好使用四位压一位,用五位的话容易爆掉...

--->关于“压位高精”,可以去看看这位大佬的博客,感jio讲的很清楚

进入正题,此题要求两个高精的“最大公约数”,那我们肯定会想到用”二进制算法“呐,

--->关于“二进制算法”,可以去看看我的另一篇博客(应该在最后面有讲到),也称“更相减损术”啦

那我直接上代码吧(反正是一道模板题...

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=1e6+5,inf=1<<29,base=10000;//10000而不是100000,不然容易爆掉!
  4 int T;
  5 int a[1000],b[1000],c[1000],f[1000];
  6 int read()
  7 {
  8     int f=1;char ch;
  9     while((ch=getchar())<‘0‘||ch>‘9‘)
 10         if(ch==‘-‘)f=-1;
 11     int res=ch-‘0‘;
 12     while((ch=getchar())>=‘0‘&&ch<=‘9‘)
 13         res=res*10+ch-‘0‘;
 14     return res*f;
 15 }
 16 void write(int x)
 17 {
 18     if(x<0)
 19     {
 20         putchar(‘-‘);
 21         x=-x;
 22     }
 23     if(x>9)write(x/10);
 24     putchar(x%10+‘0‘);
 25 }
 26 /*int gcd(int x,int y)
 27 {
 28     if(y==0)return x;
 29     else return gcd(y,x%y);
 30 }*/
 31 //欧几里得算法~显然不行
 32 void init(int a[])//压位高精度
 33 {
 34     string s;
 35     cin>>s;
 36     int len=s.length(),i,j;
 37     for(i=0;i<len;i++)
 38     {
 39         j=(len-i+3)/4;//注意是len-i+3,而不是+4!
 40         a[j]=a[j]*10+s[i]-‘0‘;
 41     }
 42     a[0]=(len+3)/4;
 43 }
 44 int com(int a[],int b[])//比较大小
 45 {
 46     if(a[0]>b[0])return 1;
 47     if(a[0]<b[0])return -1;
 48     for(int i=a[0];i>=1;i--)
 49     {
 50         if(a[i]>b[i])return 1;
 51         else if(a[i]<b[i])return -1;
 52     }
 53     return 0;
 54 }
 55 void div(int a[])//高精除2
 56 {
 57     int tmp=0;
 58     for(int i=a[0];i>=1;i--)
 59     {
 60         tmp=tmp*base+a[i];
 61         a[i]=tmp/2;
 62         tmp%=2;
 63     }
 64     while(a[a[0]]==0&&a[0]>0)a[0]--;
 65 }
 66 void jian(int a[],int b[])//高精减高精
 67 {
 68     for(int i=1;i<=a[0];i++)
 69     {
 70         a[i]-=b[i];
 71         if(a[i]<0)
 72         {
 73             a[i+1]--;
 74             a[i]+=base;
 75         }
 76         while(a[a[0]]==0&&a[0]>0)a[0]--;
 77     }
 78 }
 79 void gcd(int a[],int b[],int t)//二进制算法
 80 {
 81     if(com(a,b)==0)//如果二者相同,那就是最大公约数无疑了
 82     {
 83         T=t;
 84         return ;
 85     }
 86     if(com(a,b)<0)
 87     {
 88         gcd(b,a,t);
 89         return ;
 90     }
 91     int ta=0,tb=0;
 92     if(a[1]%2==0)
 93     {
 94         div(a);
 95         ta=1;
 96     }
 97     if(b[1]%2==0)
 98     {
 99         div(b);
100         tb=1;
101     }
102     if(ta&&tb)gcd(a,b,t+1);
103     else if(!ta&&!tb)
104     {
105         jian(a,b);
106         gcd(a,b,t);
107     }
108     else gcd(a,b,t);
109 }
110 void print(int a[])//高精输出
111 {
112     write(a[a[0]]);
113     for(int i=a[0]-1;i>0;i--)//这里可是有点学问的,不能直接像输出a[a[0]]一样输出其他几位,
114         for(int j=base/10;j>0;j/=10)//因为其他几位可能最高位为0,直接输出则0被吞掉了
115             write(a[i]/j%10);
116 }
117 void mulow(int a[],int k)//高精乘低精
118 {
119     for(int i=1;i<=a[0];i++)a[i]*=k;
120     for(int i=1;i<=a[0];i++)
121     {
122         a[i+1]+=a[i]/base;
123         a[i]%=base;
124     }
125     while(a[a[0]+1]>0)
126     {
127         a[0]++;
128         a[a[0]+1]=a[a[0]]/base;
129         a[a[0]]%=base;
130     }
131 }
132 void mulhigh(int a[],int b[])//高精乘高精
133 {
134     for(int i=1;i<=a[0];i++)
135         for(int j=1;j<=b[0];j++)
136         {
137             c[i+j-1]+=a[i]*b[j];
138             c[i+j]+=c[i+j-1]/base;
139             c[i+j-1]%=base;
140         }
141     c[0]=a[0]+b[0];
142     while(c[c[0]]==0&&c[0]>0)c[0]--;
143     for(int i=0;i<=c[0];i++)a[i]=c[i];
144 }
145 int main()
146 {
147     init(a);init(b);
148     gcd(a,b,0);
149     if(T==0)print(a);//T存储最大公约数中有多少个2
150     else
151     {
152         f[0]=f[1]=1;
153         for(int i=1;i<=T;i++)
154             mulow(f,2);//将2累乘
155         mulhigh(f,a);
156         print(f);
157     }
158     return 0;
159 }

原文地址:https://www.cnblogs.com/ljy-endl/p/11392740.html

时间: 2024-10-09 11:10:53

最大公约数(信息学奥赛一本通 1627)的相关文章

信息学奥赛一本通 5.4 状态压缩动态规划

#loj 10170. 「一本通 5.4 例 1」骑士 看数据范围n<=10,所以不是搜索就是状压dp,又因为搜索会超时所以用dp dp[i][k][j]表示现已经放到第i行,前面共有k个,这一行状态为j so,dp[i][k][j]=dp[i-1][k-num[j]][t] #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cma

【信息学奥赛一本通】第三部分_栈 ex1_4cale (中缀转后缀7符号)

其实这个中缀转后缀是费了很大功夫的,明白算法后第一次实现花了近三小时ORZ #include <stdio.h> #include <string.h> #include <ctype.h> char Mstr[511],Msta[511] = {'@'},Bstr[511]; int sta[511]; const short list[4][4] = {{0,-1,1,1},{1,0,1,1},{1,1,1,-2},{-1,-1,2,1}}; int level (

【信息学奥赛一本通】第三部分_队列 ex2_3produce 产生数

给出一个整数n(n<=2000)(代码可适用n<=10^31)和k个变换规则(k<=15). 规则:1.1个数字可以变换成另1个数字: 2.规则中右边的数字不能为零. BFS 1 #include <stdio.h> 2 #include <string.h> 3 #define maxn 1000 4 5 char num[33]; 6 int len,q[maxn],Visited[11]; 7 long long ans = 1; 8 9 int main

信息学奥赛一本通 5.1 区间类动态规划

石子合并[loj 10147] /* dp[i][j]=max or min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]) i<=k<j */ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; inline int re

信息学奥赛一本通 5.2 树形动态规划

题解在代码中 二叉苹果树[loj 10153] /* 若要留q条边便是要留q+1个点 所以记忆化搜索 dp[pos][ans]=max(dp[pos][ans],dp[l[pos]][k]+dp[r[pos]][ans-k-1]+a[pos]) 0<=k<=ans-1 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<c

信息学奥赛一本通 提高篇 序列第k个数 及 快速幂

我是传送门 这个题首先是先判断是等差还是等比数列 等差的话非常简单: 前后两个数是等差的,举个栗子: 3 6 9 12 这几个数,(我感觉 1 2 3 4并说明不了什么) 每次都加3嘛,很容易看出,第一个数是3 * 1,第二个是3 * 2....以此类推 第k个数 = (第2个数 - 第1个数) * k ; (z - y) * k % 200907 % 200907 的原因是题目要求 但是这样并不能过 hack一下 4 7 10 13 用原先的公式:(7 - 4) * 4 % 200907 =

【信息学奥赛一本通 提高组】第二章 二分与三分

一.二分 二分法,在一个单调有序的集合或函数中查找一个解,每次分为左右两部分,判断解在那个部分并调整上下界,直到找到目标元素,每次二分都将舍弃一般的查找空间,因此效率很高. 二分常见模型 1.二分答案 最小值最大(或是最大值最小)问题,这类双最值问题常常选用二分法求解,也就是确定答案后,配合贪心,DP等其他算法检验这个答案是否合理,将最优化问题转化为判定性问题.例如,将长度为n的序列ai分为最多m个连续段,求所有分法中每段和的最大值的最小是多少? 2.二分查找 用具有单调性的布尔表达式求解分界点

求后序遍历(信息学奥赛一本通 1339)

假设有棵树,长下面这个样子,它的前序遍历,中序遍历,后续遍历都很容易知道. PreOrder: GDAFEMHZ InOrder: ADEFGHMZ PostOrder: AEFDHZMG 现在,假设仅仅知道前序和中序遍历,如何求后序遍历呢?比如,已知一棵树的前序遍历是"GDAFEMHZ",而中序遍历是"ADEFGHMZ"应该如何求后续遍历? 第一步,root最简单,前序遍历的第一节点G就是root. 第二步,继续观察前序遍历GDAFEMHZ,除了知道G是root,

最大子矩阵(信息学奥赛一本通 1224)

[题目描述] 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1×1)子矩阵. [输入] 输入是一个N×N的矩阵.输入的第一行给出N(0<N≤100).再后面的若干行中,依次(首先从左到右给出第一行的N个整数,再从左到右给出第二行的N个整数……)给出矩阵中的N2个整数,整数之间由空白字符分隔(空格或者空行).已知矩阵中整数的范围都在[−127,127]. [输出] 输出最大子矩阵的大小. [输入样例] 4 0 -2 -7 0 9 2 -6 2 -4 1