数论——欧几里得算法及其扩展

欧几里得算法

思想:

欧几里德算法又称辗转相除法,是指用于计算两个a,b的最大公约数。计算公式gcd(a,b) = gcd(b,a mod b)。补充一个知识点(最小公倍数等于a*b/gcd(a,b))


证明就不证明了,这个记住的话也挺简单的
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;

int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}

int main() {
	printf("%d\n",gcd(4,16));

	return 0;
}

扩展欧几里得算法

思想:

找出一对整数x,y,使它满足方程ax+by = gcd(a, b),其中x和y可能等于或者小于0,例如gcd(6,15)=3,6*3-15*1=3,则x=6,y=-1。还有一组解就是x=-2,y=1。

代码如下:
#include <iostream>
#include <cstdio>
using namespace std;

int exgcd(int a,int b, int &x, int &y){
	if(!b) {
		x = 1; y = 0;
		return a;
	}
	int r = exgcd(b,a%b,x,y);  //这个就是a与b的最大公倍数
	int tmp = x;
	x = y;
	y = tmp - a/b*y;
	return r;
}

int main() {
	int x,y;
	exgcd(6,15,x,y);
	printf("%d %d\n",x,y);

	return 0;
}
程序怎样理解呢?我们要用递归,使得下一个x,y得到上一个x,y //这个是重点

1、我们首先想到终点的b=0的时候,gcd(a,b) = a,此时想要ax+by = gcd(a, b),只有当x=1,y=0的时候才能实现,即a*1+b*0 = a。
2、那之后怎样理解呢? 首先已知ax+by = gcd(a, b), 则由于欧几里得得到 bx1+(a%b)y1 = gcd(b,a%b).
又因为gcd(b,a%b)=gcd(a, b)。得到ax+by = bx1+(a%b)y1。 而a%b在计算机中可以表示为a - (a/b)*b(这个自己想,整形问题)
3、那么ax+by = bx1+(a-(a/b)*b)y1。 又bx1+(a-(a/b)*b)y1 = ay1+bx1-(a/b)by1。
4、最后得到 x = y1; y = x1-(a/b)y1。

下面我们来一到例题

题目链接:hdu1576 A÷B
题目大意:

A/B

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7362    Accepted Submission(s): 5844


Problem Description
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
 

Input
数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
 

Output
对应每组数据输出(A/B)%9973。
 

Sample Input
 
 
2
1000 53
87 123456789
 

Sample Output
 
 
7922
6060


题目分析:

第一次做这种题目应该是一脸蒙蔽,毕竟这是数学题嘛,我就直接给出推论

1、n=A%9973  =>  n=A-A/9973*9973

2、A/B=X  => A=BX

3、设-A/9973为Y;得出 BX+9973Y=n  所以我们求出X就知道A/B了,最后只要%9973就能得出答案

4、而已知Bx+9973y = 1(题目gcd(B,9973) = 1) =》 Bxn+9973yn = n

5、xn == X了

题解:
#include <iostream>
#include <cstdio>
using namespace std;

void exgcd(int a, int b, int &x, int &y) {
	if(!b) {
		x = 1; y = 0;
		return ;
	}
	exgcd(b,a%b,x,y);
	int tmp = x;
	x = y;
	y = tmp - a/b*y;
}

int main() {
	int t;
	scanf("%d",&t);
	for(int i = 0; i < t; i++) {
		int n,b,x,y;
		scanf("%d%d",&n,&b);
		exgcd(b,9973,x,y);
		printf("%d\n",(((x%9973+9973)%9973)*(n%9973))%9973);//%这么多9973是为了防止超出int,而前面那个(x%9973+9973)%9973是防止x为负数

	}
	return 0;
}

下面抛出两道题目给读者练习,答案会在写了之后贴在这里哟

POJ1061 青蛙的约会   、  NYOJ1013 除法表达式


如果有眼前一亮的题目或者解答欢迎和楼主讨论 ε=ε=ε=┏(゜ロ゜;)┛ 楼主的QQ486291187.





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值