#6392. 「THUPC2018」密码学第三次小作业 / Rsa (exgcd求逆元+快速幂+快速乘)
题目链接:https://loj.ac/problem/6392
题目大意:给定五个正整数c1,c2,e1,e2,N,其中e1与e2互质,且满足
c1 = m^e1 mod N
c2 = m^e2 mod N
求出正整数m
解题思路:因为e1与e2互质,所以可以找到两个整数x,y,满足e1x+e2y=1
所以m^(e1x+e2y)=m^1=m=c1^x*c2^y;
注意如果x或者y小于0时,需要求c1、c2对N的逆元
因为N的范围很大,小于2的63次方,所以不能直接乘,需要用快速乘。
求逆元的时候,无法确定N是否是素数,所以不能用费马小定理,要用扩展欧几里得
代码:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define ll long long #define N 5000005 ll mod; ll n,c1,c2,e1,e2; ll read () { char c = '\n'; while (!isdigit(c)) c = getchar(); ll res = c - '0'; c = getchar(); while (isdigit(c)) { res = res * 10 + (c - '0'); c = getchar(); } return res; } void exgcd(ll a,ll b,ll &x,ll &y,ll &d){ if(!b) x=1,y=0,d=a; else{ exgcd(b,a%b,y,x,d); y-=a/b*x; } } ll INV(ll a,ll p){ ll x,y,d; exgcd(a,p,x,y,d); return (x%p+p)%p; } ll qmul(ll a,ll b){ ll res=0; while(b){ if(b&1) res=(res+a)%mod; b>>=1; a=(a+a)%mod; } return res; } ll qpow(ll a,ll b){ ll res=1; while(b){ if(b&1) res=qmul(res,a); b>>=1; a=qmul(a,a); } return res; } int main(){ int T; T=read(); while(T--){ c1=read(),c2=read(),e1=read(),e2=read(),mod=read(); ll x,y,d; exgcd(e1,e2,x,y,d); //如果指数为负数,需要求底数对mod的逆元 if(x<0){ c1=INV(c1,mod); x=-x; } if(y<0){ c2=INV(c2,mod); y=-y; } printf("%lld\n",qmul(qpow(c1,x),qpow(c2,y))); } return 0; }