HDU 1211 (逆元)扩展欧几里得+快速幂

题目链接
Problem Description
RSA is one of the most powerful methods to encrypt data. The RSA algorithm is described as follow:

choose two large integer p, q
calculate n = p * q, calculate F(n) = (p - 1) * (q - 1)
choose an integer e(1 < e < F(n)), making gcd(e, F(n)) = 1, e will be the public key
calculate d, making d * e mod F(n) = 1 mod F(n), and d will be the private key

You can encrypt data with this method :

C = E(m) = (m ^ e) mod n

When you want to decrypt data, use this method :

M = D(c ) = (c ^ d) mod n

Here, c is an integer ASCII value of a letter of cryptograph and m is an integer ASCII value of a letter of plain text.

Now given p, q, e and some cryptograph, your task is to “translate” the cryptograph into plain text.

Input
Each case will begin with four integers p, q, e, l followed by a line of cryptograph. The integers p, q, e, l will be in the range of 32-bit integer. The cryptograph consists of l integers separated by blanks.

Output
For each case, output the plain text in a single line. You may assume that the correct result of plain text are visualable ASCII letters, you should output them as visual letters with no blank between them.

Sample Input
101 103 7 11
7716 7746 7497 126 8486 4708 7746 623 7298 7357 3239

Sample Output
I-LOVE-ACM.

题意:
根据RSA加密算法的要求,我们可以得到下面的信息:

  1. n = p*q;
  2. F = (p-1)*(q-1);
  3. 存在一个整数e与F互斥;
  4. 整数d计算方法为 d*e % F = 1;(用扩展欧几里得实现)
  5. 需要求m = cd mod n;(用快速幂实现)

分析:
首先要了解扩展欧几里得是什么,在这里我就不赘述了,网上有很多博主已经分析的很好,这里我只是简单的说如何应用到这个题目中去。

我们知道扩展欧几里得可以求出线性方程ax+by=gcd(a,b)x与y的解;

我们还需要知道逆元的定义,即ax =1 mod n;

这样的话,就可以在保证a与b互质的前提下,将线性方程修改为ax + by=1;

等式两边同时模b,那么就得到
ax = 1 mod b(这就是求a的逆元嘛)

我们根据题意中我提到的“4”那个等式“d*e%F=1”等价变换为

e*d = 1 mod F,其中 e与F互质

为啥要求互质呢?先引入一个贝祖定理:

即如果a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。

换句话说,如果ax+by=m有解,那么m一定是gcd(a,b)的若干倍。(可以来判断一个这样的式子有没有解)
有一个直接的应用就是 如果ax+by=1有解,那么gcd(a,b)=1;

ps:这篇文章写了关于扩展欧几里得求逆元的讲解,自己感觉还行。

这样我们就求出了d,剩下的就是快速幂的内容了。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <map>
#include <set>
#include <cstring>
#include <stack>
#include <string>
using namespace std;

typedef long long ll;
const int N = 1e5+199;
const double Pi = acos(-1);

ll Ext_gcd(ll a,ll b,ll &x,ll &y){
    
    
    if(b==0){
    
    
        x=1;
        y=0;
        return a;
    }
    ll ret=Ext_gcd(b,a%b,x,y);
    ll t = x;
    x = y;
    y=t-(a/b)*y;
    return ret;
}

ll Mul_Pow(ll a,ll b,ll mod){
    
    
    ll res=1;
    while(b>0){
    
    
        if(b&1)
            res = res * a % mod;
        a = a * a % mod;
        b>>=1;
    }
    return res;
}
int main()
{
    
    

    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    ll p,n,F,q,e,val,d,x,y,ans;
    int l;
    while(scanf("%lld%lld%lld%d",&p,&q,&e,&l)!=EOF){
    
    
        n = p*q;
        F = (p-1)*(q-1);
        d = Ext_gcd(e,F,x,y);
        d = (x%F+F)%F;//因为x有可能为负数

        for(int i=0;i<l;i++){
    
    
            scanf("%lld",&val);
            val = Mul_Pow(val,d,n);
            printf("%c",char(val));
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/115448643