题目来源:http://acm.nyist.net/JudgeOnline/problem.php?pid=769

乘数密码

时间限制:1000 ms  |  内存限制:65535 KB
难度:1
 
描述

乘数密码也是一种替换密码,其加密变换是将明文字母串逐位乘以密钥k并进行模运算,数学表达式如下:

E(m)=k*m mod q,   gcd(k,q)=1 (即k,q互素)。

当k与q互素时,明文字母加密成密文字母的关系为一一映射。

现有一经过乘法加密的密文,请破译出它的明文。

 
输入
输入包含多组数据,不超过1000组。
每组包含一个字符串和一个正整数k,字符串全部由大写字母组成,长度不超过50,k是与q互素的数,q=26,k<26。
输出
每组输出数据单独占一行,输出对应的明文。
样例输入
ILOVEYOU 3
样例输出
UVWHKIWY

分析:
1:加密 E(m) = k*m % q 且 gcd(k,q)=1;
2:解密 m = E(m) * k^-1(mod q) mod q 。
k^-1(mod q)为 kx≡1(mod q)中 x 的值。 
代码如下:
#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#define N 55
using namespace std;
char str[N];
// 扩展欧几里得 , 得到 x, y, d等式 ax + by =d
int extend_gcd(int a, int b, int&x, int &y)
{
    if(b==0) {x=1; y=0; return a;}
    int d=extend_gcd(b,a%b, y,x);
    y-=a/b *x;
}
// **************求逆元 ,在 已知 gcd(k,n) =1 的情况
// kx =1(mod n)
int mod_reverse(int k, int n)
{
    int x,y;
    extend_gcd(k,n,x,y)%n;
     return (x%n +n)%n;
}
int main(){
    while(cin>>str)
    {
        int k;
        scanf("%d",&k);
        for(int i=0; i<strlen(str) ; i++)
        {
            str[i]  = (str[i] -'A') * mod_reverse(k,26) %26 +'A';
            printf("%c",str[i]);
        }
        printf("\n");
    }
    return 0;
}