扩展欧几里得:求逆元,RSA,谈恋爱
(2019-11-07 13:34:49)分类: 数论 |
同余方程:
1)如果两个整数a,b,那么必定存在公式a*x+b*y=gcd(a,b);
2)方程 ax + by = m 有解的必要条件是 m mod gcd(a,b) = 0
同余:设m是给定的一个正整数,a、b是整数,若满足 m|(a-b),则称a与b对模m同余,记为a≡b(mod m),或记为a≡b(m)
意义相当于 a=b+km(k∈Z);
扩展欧几里得算法可以用来计算模反元素(也叫模逆元)
一)碾转相除法求gcd
int gcd(int m,int n){ return
m%n==0?n:gcd(n,m%n);}
int gcd(int m,int n){ return
n==0 ? m:gcd(n,m%n);}//或
二)扩展欧几里德,可以同时求出最小的x,y;
模板:
int gcdEx(int a,int b,int*x,int*y)
{
if(b==0)
{
*x=1,*y=0 ;
return a ;
}
else
{
int r=gcdEx(b,a%b,x,y);
int t=*x ;
*x=*y ;
*y=t-a/b**y ;
return r ;
}
}
一)同余方程 P1082 扩展欧几里德模板
求关于x的同余方程 ax≡1(mod b) 的最小正整数解。
输入格式
一行,包含两个正整数 a,b,用一个空格隔开。
输出格式
一个正整数 x_0,即最小正整数解。输入数据保证一定有解。
输入输出样例
输入 #1复制
3 10
输出 #1复制
7
说明/提示
【数据范围】
对于 40%的数据,2≤b≤1,000;
对于 60%的数据,2≤b≤50,000,000;
对于 100%的数据,2≤a,b≤2,000,000,000。
NOIP 2012 提高组 第二天 第一题
可以用暴力枚举x,拿40-60分,但是要AC,需要使用扩展欧几里德
条件 ax mod b = 1,实质是 ax + by = 1,y是任意整数,因为by mod b一定等于0;
using namespace std;
int a,b,x,y,k;
void exgcd(int a,int b){
if(b==0) {
x=1,y=0;
return;
}
exgcd(b,a%b);
k=x, x=y,
y=k-a/b*y;
return;
}
int main()
{
ios::sync_with_stdio(false);
cin>>a>>b;
exgcd(a,b);
cout<<(x+b)%b;
}
二)A/B hdu1576 逆元模板
要求(A/B) mod 9973,但由于A很大,我们只给出n(n=A mod 9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
Input
数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
Output
对应每组数据输出(A/B) mod 9973。
Sample Input
2
1000 53
87 123456789
Sample Output
7922
6060
逆元的定义:
每个数a均有唯一的与之对应的乘法逆元x,使得a*x≡1(mod M),一个数有逆元的充分必要条件是gcd(a,M)=1,此时a的逆元x唯一存在。
在这题里,M==9973,与B存在gcd(B,M)==1的关系。因此B相对于9973的逆元是x.
A/B mod 9973的意义,等价于A*x mod 9973。
而(A+n) mod 9973 =n,即 A=n (mod 9973),所以答案是n*x
逆元的含义:模n意义下,1个数a如果有逆元x,那么除以a相当于乘以x。
解法一:扩展欧几里德,也就是求逆元
给定模数9973,求B的逆元,相当于求解Bx=1(mod 9973) ,
即存在B*x+9973*y=1的关系;y可以是任何数;
两侧取mod 9973,就得到
B*x mod 9973 =1
#include "bits/stdc++.h"
using namespace std;
const int md=9973;
typedef long long ll;
ll ex_gcd(ll a,ll b,ll &x,ll &y){
if(b ==
0){
x = 1;
y = 0;
return a;
}
ll r =
ex_gcd(b,a%b,y,x);
y -=
x*(a/b);
return
r;
}//扩展欧几里得模板
int main(){
ll
n,B,t,gcd,x,y;
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&B);
gcd = ex_gcd(B,md,x,y);
x =(x*n)%md; //x=A/B,贝祖定理, n =A mod 9973
x = (x+md) % md;
printf("%lld\n",x);
}
return
0;
}
解法二:相当于解释了贝祖定理的形成。
本題由题意n=A mod 9973,
改写成n=A-A/9973*9973
因为A/B=X;所以A=n+A/9973*9973=BX;
得到 BX-9973y=n;
因为gcd(B,9973)==1,所以B*X+9973*y==1存在x,y的整数解,
因此b*x-n一定存在正整数解,并且等于9973*n
由x*B-n=9973y,得到(x*B-n)mod 9973=0,类似《我家的门牌号》
using namespace std;
int main()
{
int t, i, j;
long long n,
b, a=9973;
scanf("%d",
&t);
while(t--)
{
scanf("%lld%lld", &n, &b);
for(x=0; x < a; j++)
1)如果两个整数a,b,那么必定存在公式a*x+b*y=gcd(a,b);
2)方程 ax + by = m 有解的必要条件是 m mod gcd(a,b) = 0
同余:设m是给定的一个正整数,a、b是整数,若满足 m|(a-b),则称a与b对模m同余,记为a≡b(mod m),或记为a≡b(m)
意义相当于 a=b+km(k∈Z);
扩展欧几里得算法可以用来计算模反元素(也叫模逆元)
一)碾转相除法求gcd
int gcd(int m,int n){
int gcd(int m,int n){
二)扩展欧几里德,可以同时求出最小的x,y;
模板:
{
}
一)同余方程 P1082 扩展欧几里德模板
求关于x的同余方程 ax≡1(mod b) 的最小正整数解。
输入格式
一行,包含两个正整数 a,b,用一个空格隔开。
输出格式
一个正整数 x_0,即最小正整数解。输入数据保证一定有解。
输入输出样例
输入 #1复制
3 10
输出 #1复制
7
说明/提示
【数据范围】
对于 40%的数据,2≤b≤1,000;
对于 60%的数据,2≤b≤50,000,000;
对于 100%的数据,2≤a,b≤2,000,000,000。
NOIP 2012 提高组 第二天 第一题
可以用暴力枚举x,拿40-60分,但是要AC,需要使用扩展欧几里德
条件 ax mod b = 1,实质是 ax + by = 1,y是任意整数,因为by mod b一定等于0;
using namespace std;
int a,b,x,y,k;
void exgcd(int a,int b){
}
int main()
{
}
二)A/B hdu1576 逆元模板
要求(A/B) mod 9973,但由于A很大,我们只给出n(n=A mod 9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
Input
数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
Output
对应每组数据输出(A/B) mod 9973。
Sample Input
2
1000 53
87 123456789
Sample Output
7922
6060
逆元的定义:
每个数a均有唯一的与之对应的乘法逆元x,使得a*x≡1(mod M),一个数有逆元的充分必要条件是gcd(a,M)=1,此时a的逆元x唯一存在。
在这题里,M==9973,与B存在gcd(B,M)==1的关系。因此B相对于9973的逆元是x.
A/B mod 9973的意义,等价于A*x mod 9973。
而(A+n) mod 9973 =n,即 A=n (mod 9973),所以答案是n*x
逆元的含义:模n意义下,1个数a如果有逆元x,那么除以a相当于乘以x。
解法一:扩展欧几里德,也就是求逆元
给定模数9973,求B的逆元,相当于求解Bx=1(mod 9973) ,
即存在B*x+9973*y=1的关系;y可以是任何数;
两侧取mod 9973,就得到
B*x mod 9973 =1
#include "bits/stdc++.h"
using namespace std;
const int md=9973;
typedef long long ll;
ll ex_gcd(ll a,ll b,ll &x,ll &y){
}//扩展欧几里得模板
int main(){
}
解法二:相当于解释了贝祖定理的形成。
本題由题意n=A mod 9973,
改写成n=A-A/9973*9973
因为A/B=X;所以A=n+A/9973*9973=BX;
得到 BX-9973y=n;
因为gcd(B,9973)==1,所以B*X+9973*y==1存在x,y的整数解,
因此b*x-n一定存在正整数解,并且等于9973*n
由x*B-n=9973y,得到(x*B-n)mod 9973=0,类似《我家的门牌号》
using namespace std;
int main()
{