A/B
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5717 Accepted Submission(s): 4481
一、欧几里德算法就是我们熟悉的辗转相除法用来求两个数的最大公约数。即:gcd(a,b)=gcd(b,a%b).
二、那么什么是扩展欧几里德算法?扩展欧几里德算法是用来在已知a, b求解一组x,y,使它们满足贝祖等式: ax+by = gcd(a, b) =d(解一定存在,根据数论中的相关定理)。扩展欧几里德常用在求解模线性方程及方程组中。
解题思路:
1) n=a%9973, 那么n=a-(a/9973)*9973(关于这个式子的解释:如:7%3=2...1 这是我们在日常数学中的写法,那么我们可以把这个式子转换一下,2=7/3,1=7-2*3,1=7-(7/3)*3),注意:a/b所得是整数。
2) 然后我们要把现在有的条件转换成扩展欧几里德,已知n,b,gcd(b,9973) (利用扩展欧几里德,我们可以知道gcd(b,9973)=1=bx+9973y)。题目让我们去求(a/b)%9973,我们如果把a/b求出来那么答案也就知道了。不妨设 a/b=x1,那么a=b*x1,那么1中的式子通过替换得到:n=bx1-(bx1/9973)*9973 ,咦~有没有发现,如果设y1=-(bx1/9973).那么我们的式子最终变成了n=bx1+9973y1 是不是快和已知的那个gcd(b,9973)联系起来了。
3) 通过继续了解扩展欧几里德算,我们了解到欧几里德算法的终止条件为:已经ax+by = gcd(a, b) , 当a=gcd,b=0的时候终止。那么,这是否给我们求解x,y提供一种思路呢?看,这时候,只要a的系数为1,即x=1. b的系数为0,即y=0. 这时候我们就有 a *1 + b*0 =gcd 这就是我们算法终止时候的状态,那么我们如何通过最终状态进行反推,求得最初状态的x和y呢?
4) 我们知道ax+by = gcd(a, b) ,那么它的下个状态为b*x1+(a%b)*y1=gcd(b,a%b) 我们知道a%b=a-(a/b)*b,代入式子即 a*y1+b(x1-(a/b)*y1)=gcd(b,a%b) 和原来的式子相比我们发现x=y1,y=x-(a/b)*y1,这样我们就把欧几里德的全过程表示出来了,我们就可以通过递归实现这个算法了。
5) 了解到欧几里德的全过程,我们了也就可以联系我们一开始的两个式子:gcd(b,9973)=1=bx+9973y和n=b*x1+9973*y1,即gcd(b,9973)=1=bx+9973 是我们的最终状态,我们通过递归调用,将x=y1,y=x-(a/b)*y1写在递归调用后面,最后一定能求出 x,如果把最终状态两边同时乘以n 变成n=b*x*n+9973*n*y 即x1=x*n,y1=n*y.。x1就是我们一开始想求得那个a/b !
欧几里德算法是自己的数论入门,也是看了两天,算是理解,如果不明白请戳(这些讲的都比我详细,我也是刚理解):
:http://blog.csdn.net/zhjchengfeng5/article/details/7786595
:http://blog.csdn.net/liuchang54/article/details/44065651
扩展欧几里得算法:http://www.acmerblog.com/extend-gcd-5610.html
#include#define mod 9973using namespace std;int x;int y;void gcd(int a,int b){ int temp; if(b==0) { x=1; y=0; return; } else { gcd(b,a%b); temp=x; x=y; y=temp-(a/b)*y; }}int main(){ int n; int b; int t; cin>>t; while(t--) { cin>>n>>b; gcd(b,mod); x=(x%mod+mod); x*=n; cout< <