扩展欧几里德算法模版题(求逆元+分析+题目)HDU1576 A/B
2016-11-18 16:56
316 查看
首先给大家普及一下什么是扩展欧几里德算法,它是由欧几里德算法演变的,即我们常说的辗转相除法。
那么对于不完全为0的非负整数,a,b,gcd(a,b)表示a,b的最大公约数,必然存在整数对x,y使得 gcd(a,b)=ax+by
设 a>b。
1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2,a>b>0 时
设 ax1+ by1= gcd(a,b);
bx2+ (a mod b)y2= gcd(b,a mod b);
根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
则:ax1+ by1= bx2+
(a mod b)y2;
即:ax1+ by1= bx2+
(a - [a / b] * b)y2=ay2+ bx2-
[a / b] * by2;
也就是ax1+ by1 == ay2+ b(x2-
[a / b] *y2);
根据恒等定理得:x1=y2;
y1=x2- [a / b] *y2;
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于
x2,y2.
上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束,最后通过线性关系求出最初的x,y。
扩展欧几里德算法
代码一如下:
代码二如下:
//递归最底层必定是a==gcd(a,b),所以x==1,b*y任意,令y=0,方便求解。 通过以上介绍的相邻两层递归之间线性关系,求出最初的x,y。
//找到一组数对x,y使得等式成立,但并不是最简的整数,也不是非负的。下面的题目会涉及到。
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4753 Accepted Submission(s): 3701
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
(之前写的思路简直就是扯淡,现在终于找到了方向)思路:一个很大的数,在进行+、* 运算时,不断的取余是不影响结果的,但是 “-” 会出现负数,只要+mod在再%mod就行了,但是 /(除法)需要求逆元。所以这个就是个模板题。
代码如下:
思路一(正解):
思路二:
那么对于不完全为0的非负整数,a,b,gcd(a,b)表示a,b的最大公约数,必然存在整数对x,y使得 gcd(a,b)=ax+by
求解 x,y的方法的理解
设 a>b。1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2,a>b>0 时
设 ax1+ by1= gcd(a,b);
bx2+ (a mod b)y2= gcd(b,a mod b);
根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
则:ax1+ by1= bx2+
(a mod b)y2;
即:ax1+ by1= bx2+
(a - [a / b] * b)y2=ay2+ bx2-
[a / b] * by2;
也就是ax1+ by1 == ay2+ b(x2-
[a / b] *y2);
根据恒等定理得:x1=y2;
y1=x2- [a / b] *y2;
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于
x2,y2.
上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束,最后通过线性关系求出最初的x,y。
扩展欧几里德算法
代码一如下:
代码二如下:
//递归最底层必定是a==gcd(a,b),所以x==1,b*y任意,令y=0,方便求解。 通过以上介绍的相邻两层递归之间线性关系,求出最初的x,y。
//找到一组数对x,y使得等式成立,但并不是最简的整数,也不是非负的。下面的题目会涉及到。
A/B
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4753 Accepted Submission(s): 3701
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
(之前写的思路简直就是扯淡,现在终于找到了方向)思路:一个很大的数,在进行+、* 运算时,不断的取余是不影响结果的,但是 “-” 会出现负数,只要+mod在再%mod就行了,但是 /(除法)需要求逆元。所以这个就是个模板题。
代码如下:
思路一(正解):
#include <stdio.h> #include <stdlib.h> #define m 9973 int exGcd(int a,int b,int &x,int &y) { if(b==0) { x=1;y=0; return a; } int r=exGcd(b,a%b,x,y); int t=x;x=y;y=t-a/b*y; return r; } int main() { int n,b,t,x,y; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&b); exGcd(b,m,x,y); x=(x%m+m)%m; //默认 printf("%d\n",(x*n)%m); //正常情况这里要求x*A的,但是A比较大给了A%m取余了。 } return 0; }
思路二:
//当然也可以从原理上分析这个题目因为A%B==0,假设A/B=T;模拟一下T的值就可以了,易犯错误(A/B)%9973!=(A%9973)/(B%9973) #include<stdio.h> int main() { long long a,b; int k=9973; long long w; int t; scanf("%d",&t); while(t--) { scanf("%I64d%I64d",&a,&b); int t=1; while(w%k!=a) w=(t++)*b; printf("%I64d\n",(t-1)%k); } return 0; }
相关文章推荐
- 扩展欧几里德求逆元模版
- 扩展欧几里德算法求逆元3
- 用扩展的欧几里德算法求最大公约数以及逆元
- [kuangbin带你飞]专题十六 KMP & 扩展KMP & Manacher 题目分析
- hdu1576 A/B(扩展的欧几里德算法)
- 让我们一起来对VSTS扩展开发吧------制作自己的VSTS模版----第五节 分析过程模版的定义文件
- 实例分析ASP上传漏洞入侵实战及扩展
- 使用Windbg和SoS扩展调试分析.NET程序
- 实例分析ASP上传漏洞入侵实战及扩展
- ucfs分析扩展
- 让我们一起来对VSTS扩展开发吧------制作自己的VSTS模版----第二节 下载VSTS模版
- 基于.NET 2.0的GIS开源项目SharpMap分析手记(六):SharpMap的功能扩展之路
- 一个词法分析的题目
- 使用Windbg和SoS扩展调试分析.NET程序
- FTP协议的分析和扩展
- 扩展的欧几里德算法
- SCJP考试中的线程题目分析
- 让我们一起来对VSTS扩展开发吧------制作自己的VSTS模版----第四节 VSTS团队项目的真删除
- 让我们一起来对VSTS扩展开发吧------制作自己的VSTS模版----第一节 序