Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 81739 | Accepted: 14151 |
Description
Input
Output
Sample Input
1 2 3 4 5
Sample Output
4
这一题初看起来很简单,但是当测试的数据比较大的时候,传统的简单算法会耗时,甚至对于某些测试数据不能快速判断出来。下面我们介绍欧几里得,扩展的欧几里得算法。
欧几里得算法可能是世界上最早的算法之一,是由古希腊伟大的数学家欧几里得提出的用来计算两个正整数最大公约数(GCD)的算法。在“来自圣经的算法”的网络评选中,其位居榜首,可见该算法的无穷魅力。 下面让我们去体会GCD算法的魅力:
定理一, (GCD递归定理)对任意非负的整数a和任意的正整数b, GCD(a,b) = GCD(b, a mod b) 引理:如果 a | b 且 b | a,那么有 a = b 或者 a = -b 证明:(1) a | b ,则存在整数 m ,使得 b = m* a 。等式两边都添加绝对值我们得到:|b| = |m| * |a| ,又有b | a,知b 不等于 0 ,那么显然 m 不为0. 我们可得 |b| = |m| * |a| >= 1 * |a| = |a|。 (2)同理可得:|a| >= |b| 综合(1)、(2)可得:|a| = |b| ,即a = b 或者 a = -b。
下面我们来证明GCD递归定理: 思路:如果我们可以证明GCD(a,b) 和GCD(b,b mod a)可以相互整除,这样我们根据上面的引理便可得到 GCD(a,b) = GCD(b, b mod a)。
设 d = GCD(a,b),那么有 d | a 和 d | b。那么由整除定理可得 (a mod b) = a - q * b,其中q = a/b 的向下取整值。那么我们得到 (a mod b) 为 a 和 b的一个线性组合,那么有 d | a, d | b 可得 d |(a mod b) 。同时又有 d | b, 那么 d | GCD(b, a mod b),即: GCD(a ,b )| GCD(b,a mod b)。 同理我们可以得到:GCD(b,a mod b) | GCD(a,b)。 综上所述,加上我们的引理: GCD(a , b) = GCD( b,a mod b)。
欧几里得算法的代码实现:
//迭代版本
int ITERATIVE-GCD(int a, int b) { int r = a % b; while (r) { a = b; b = r; r = a % b; } return b; }//递归版本int RECURSIVE-GCD(int a, int b) { if (b == 0) return a; else return RECURSIVE-GCD(b, a % b); }
扩展的欧几里得:
int Euclid_Extended(int a,int b,int &x0,int &y0) { int t,d; if (b==0) { x0=1; y0=0; return a; } d=Euclid_Extended(b,a%b,x0,y0); t=x0; x0=y0; y0=t-a/b*y0; return d; }
函数返回值为gcd(a,b),并顺带解出ax+by=gcd(a,b)的一个解x0,y0, 对于不定方程ax+by=c的通解为: x=x0*c/d+b/d*t y=y0*c/d-a/d*t 当c%gcd(a,b)!=0时,不定方程无解.所以对于这一题:#include <iostream> #include <cstdio> #include <cmath> #include <fstream> using namespace std; long long Euclid_Extended(long long a,long long b,long long &x0,long long &y0) //扩展欧几里德算法,函数返回值为gcd(a,b) { //并顺带解出ax+by=gcd的一个解x0,y0 long long t,d; if (b==0) { x0=1; y0=0; return a; } d=Euclid_Extended(b,a%b,x0,y0); t=x0; x0=y0; y0=t-a/b*y0; return d; } int main() { long long x,y,m,n,L; long long a,b,c,x0,y0; //ifstream fin("e:\\data2.txt"); //ofstream fout("e:\\1.txt"); //while(fin>>x>>y>>m>>n>>L) while(cin>>x>>y>>m>>n>>L) { a=n-m; b=L; c=x-y; long long d=Euclid_Extended(a,b,x0,y0); if (c%d!=0) { cout<<"Impossible"<<endl; //fout<<"Impossible"<<endl; } else { long long k; k=x0*c/d; long long t=(b/d)>0?(b/d):(-b/d); if (k<0) { while (k<0) k+=t; } if (k>0) { while(k>0) k-=t; k+=t; } cout<<k<<endl; //fout<<k<<endl; } } return 0; }
参考:http://blog.csdn.net/zjsxzjb/article/details/6262667
参考:http://blog.tianya.cn/blogger/post_read.asp?BlogID=3880799&PostID=35359648