传送门

Description

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

Input

共两行: 第一行:一个数A。 第二行:一个数B。

Output

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

Sample Input

12
54

Sample Output

6

Hint

对于100%的数据,0 < A , B ≤ 10 ^ 10000。

Solution

如果你觉得这是个裸的gcd的话,你会发现高精度乘除取余在这么大的位数下就是找死。考虑使用高精度运算复杂度更低的更损相减法。但是朴素的更损相减法是\(O(n)\)的。需要进行优化。

考虑对于两个数\(a,b\)两数共可能出现以下情况:

(不妨设\(a>b\))

1、\(a\)是偶数,\(b\)不是。那么\(gcd(a,b)=gcd(\frac{a}{2},b)\)。

2、\(a\)不是偶数,\(b\)是。那么\(gcd(a,b)=gcd(a,\frac{b}{2})\)。

3、\(a,b\)都是偶数,那么\(gcd(a,b)=2~\times~gcd(\frac{a}{2},\frac{b}{2})\)。

4、\(a,b\)都不是偶数,那么应用更损相减法,\(gcd(a,b)=gcd(b,a-b)\)。

考虑这么做的复杂度。当两个数是奇数的时候,需要更损相减法,两个奇数做差的答案是一个偶数。每次其中一个数除二后最多做一次更损相减。

考虑一个数除二的最大次数是\(logn\)的。所以优化后更损相减部分的复杂度是\(O(logn)\)的。

Code

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#define rg register
#define ci const int
#define cl const long long int typedef long long int ll; namespace IO {
char buf[50];
} template<typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while(ch>'9'||ch<'0') lst=ch,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if (lst=='-') x=-x;
} template<typename T>
inline void write(T x,const char aft,const bool pt) {
if(x<0) {putchar('-');x=-x;}
int top=0;
do {
IO::buf[++top]=x%10+'0';
x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
} template <typename T>
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
template <typename T>
inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
template <typename T>
inline T mabs(const T a) {if(a<0) return -a;return a;} template <typename T>
inline void mswap(T &a,T &b) {T temp=a;a=b;b=temp;} struct Bignum {
short int num[10010],len;
void clear() {memset(num,0,sizeof num);len=0;}
void operator-=(const Bignum &others) {
for(rg int i=1;i<=this->len;++i) {
this->num[i]-=others.num[i];
while(this->num[i]<0) {
this->num[i]+=10,--this->num[i+1];
}
}
while(!this->num[this->len]) --this->len;
if(!this->len) ++this->len;
}
bool operator!=(const Bignum &others) {
if(this->len!=others.len) return true;
for(rg int i=1;i<=this->len;++i) if(this->num[i] != others.num[i]) return true;
return false;
}
bool operator<(const Bignum &others) {
if(this->len!=others.len) return this->len<others.len;
for(rg int i=len;i;--i) if(this->num[i]!=others.num[i]) return this->num[i]<others.num[i];
return false;
}
Bignum operator*(const Bignum &others) {
Bignum _ans;_ans.clear();
int llen=this->len+others.len+5;
for(rg int i=1;i<=this->len;++i) {
for(rg int j=1;j<=others.len;++j) {
_ans.num[i+j-1]+=this->num[i]*others.num[j];
}
}
for(rg int i=1;i<=llen;++i) {
_ans.num[i+1]+=_ans.num[i]/10;
_ans.num[i]%=10;
}
_ans.len=llen;
while(!_ans.num[_ans.len]) --_ans.len;
if(!_ans.len) _ans.len=1;
return _ans;
}
};
Bignum a,b,ans; char MU[10010];
int cnt; void dv(Bignum&);
void mul(Bignum&);
void init(Bignum&,int);
void print(Bignum&); int main() {
scanf("%s",MU+1);init(a,strlen(MU+1));
scanf("%s",MU+1);init(b,strlen(MU+1));
ans.num[1]=1;ans.len=1;
while(a != b) {
bool flag=false;
if(!((int(a.num[1])) & 1)) {dv(a);flag=true;}
if(!((int(b.num[1])) & 1)) {dv(b);if(flag) mul(ans);flag=true;}
if(flag) continue;
// print(a);puts("\nemm");print(b);putchar('\n');
if(a < b) {b-=a;}
else {a-=b;}
}
ans=ans*a;
print(ans);putchar('\n');
return 0;
} void init(Bignum &k,int l) {
for(rg int i=l;i;--i) k.num[++k.len]=MU[i]-'0';
} void dv(Bignum &k) {
int lst=0;
for(rg int i=k.len;i;--i) {
int _temp=k.num[i]+(lst<<1)+(lst<<3);
int _ans=_temp/2;
if(_temp & 1) lst=1;else lst=0;
k.num[i]=_ans;
}
while(!k.num[k.len]) --k.len;
return;
} void mul(Bignum &k) {
int lst=0;k.len+=2;
for(rg int i=1;i<=k.len;++i) {
k.num[i]*=2;
k.num[i]+=lst;
lst=k.num[i]/10;k.num[i]%=10;
}
while(!k.num[k.len]) --k.len;
if(!k.len) ++k.len;
return;
} void print(Bignum &k) {
// printf("%d\n",k.len);
for(rg int i=k.len;i>0;--i) putchar(k.num[i]+'0');
}

Summary

在高精度运算下求gcd,如果两数特大可以考虑使用优化后的更损相减。但是需要注意的是更损相减法的常数在极端情况下大概会达到\(4\)倍。而欧几里得算法的常数小于\(1\)。在取模计算量可以忽略的情况下应尽量选择欧几里得算法。

再说一句GCD真的不是什么党……

【数论数学】【P2152】【SDOI2009】Super GCD的更多相关文章

  1. [bzoj]2705: [SDOI2012]Longge的问题[数论][数学][欧拉函数][gcd]

    [bzoj]P2705 OR [luogu]P2303 Longge的问题 Description Longge的数学成绩非常好,并且他非常乐于挑战高难度的数学问题.现在问题来了:给定一个整数N,你需 ...

  2. UVA12716 GCD XOR 数论数学构造

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u010682557/article/details/36204645 题目给你一个N,让你求 两个数 ...

  3. 数学--数论--HDU 5019 revenge of GCD

    Revenge of GCD Problem Description In mathematics, the greatest common divisor (gcd), also known as ...

  4. 数学--数论--HDU1792A New Change Problem(GCD规律推导)

    A New Change Problem Problem Description Now given two kinds of coins A and B,which satisfy that GCD ...

  5. 数学 赛码 1010 GCD

    题目传送门 /* 数学:官方题解 首先,数组中每个元素至少是1 然后对于任意一个询问Li, Ri, Ansi, 说明Li ~ Ri中的元素必定是Ansi的倍数,那么只需将其与Ansi取最小公倍数即可 ...

  6. 【数学】XMU 1597 GCD

    题目链接: http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1597 题目大意: 求(am-bm, an-bn),结果取模1000000007,a,b ...

  7. noip2017考前基础复习——数论数学

    ·最大公约数 gcd 辗转相除法  gcd(a,b)=gcd(b,a%b) int gcd(int x,int y){ ) return x; return gcd(y,x%y); } 效率O(log ...

  8. P2152 [SDOI2009]SuperGCD 未完成

    辗转相减求a,b的gcd其实可以优化的: 1.若a为偶数,b为奇数:gcd(a,b)=gcd(a/2,b) 2.若a为奇数,b为偶数:gcd(a,b)=gcd(a,b/2) 3.若a,b都是偶数:gc ...

  9. 数学:莫比乌斯反演-GCD计数

    Luogu3455:莫比乌斯反演进行GCD计数 莫比乌斯反演就是用来解决这一类问题的,通常f函数是要求的那个,F函数是显然的 这样利用F的结果就可以推出来f的结果 在计算结果的时候整除分快儿一下就可以 ...

随机推荐

  1. unity中虚拟摇杆的实现

    实现效果: 实现: 使用NGUI添加虚拟摇杆背景和其子物体按钮,为按钮Attach  boxcollider和ButtionScript.为按钮添加如下脚本: 注意:其中的静态属性可以在控制物体移动的 ...

  2. Java开发工程师(Web方向) - 03.数据库开发 - 第4章.事务

    第4章--事务 事务原理与开发 事务Transaction: 什么是事务? 事务是并发控制的基本单位,指作为单个逻辑工作单元执行的一系列操作,且逻辑工作单元需满足ACID特性. i.e. 银行转账:开 ...

  3. linux系统简单命令

    # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # cat /proc/cpuinfo # 查看CPU信息 # hostn ...

  4. 小程序解析html和富文本编辑内容【亲测有效】

    首先去 https://github.com/icindy/wxParse 下载wxParse,只拷贝wxParse文件夹即可. 1.引入wxss @import "../../util/w ...

  5. 【转】Haml 这货是啥? 附参考

    Haml是一种用来描述任何XHTML web document的标记语言,它是干净,简单的.而且也不用内嵌代码.Haml的职能就是替代那些内嵌代码的page page templating syste ...

  6. leetcode9_C++判断一个整数是否是回文数

    判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 输出: true 示例 2: 输入: - 输出: false 解释: 从左向右读, 为 - ...

  7. Notes of the scrum meeting before publishing(12.19)

    meeting time:18:30~20:30p.m.,December 19th,2013 meeting place:3号公寓一层 attendees: 顾育豪                  ...

  8. Median of Two Sorted Arrays(hard)

    题目要求: 有两个排序的数组nums1和nums2分别为m和n大小. 找到两个排序数组的中位数.整体运行时间复杂度应为O(log(m + n)). 示例: 我的方法: 分别逐个读取两个数组的数,放到一 ...

  9. lintcode-191-乘积最大子序列

    191-乘积最大子序列 找出一个序列中乘积最大的连续子序列(至少包含一个数). 样例 比如, 序列 [2,3,-2,4] 中乘积最大的子序列为 [2,3] ,其乘积为6. 标签 子数组 领英 动态规划 ...

  10. EasyUI 学习笔记

    EasyUI常见错误 1 . 无论是用HMTL形式实现组件还是使用代码 + HTML 形式实现组件 , 在为组件设置属性时 , 要注意属性值的类型问题 string:必须加引号 number:不加任何 ...