#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;
}

 

posted @ 2019-05-06 20:50  两点够吗  阅读(362)  评论(0编辑  收藏  举报