解密(拓展欧几里的)

链接:https://ac.nowcoder.com/acm/contest/1085/D
来源:牛客网

小sun为了考试最近正在复习密码学,他现在遇到了一个问题:有一个由大小写字母组成的密文,要解密成明文。小sun知道怎么算,但是小sun很懒,他并不想算,所以他想让你帮他算算。

加密算法如下:

若明文为x,密文c为
C≡k1∗x+k2(mod  26)

二十六个英文字母依次标号为0~25,比如A(a)为0,Z(z)为25


输入描述:

第一行,两个整数k1,k2
第二行一个字符串,代表密文(长度不超过1000)
保证gcd(k1,26)=1

输出描述:

输出一行字符串,为解密后的字符串
示例1

输入

复制
45 66
RmppuQuzpt

输出

复制
HelloWorld

备注:

k1,k2均在int以内
密文仅包含大小写字母 A(a)~Z(z)

大写字母输出大写字母,小写字母对应输出小写字母


其实这个题可以直接枚举字符判断的,
也可以用拓展欧几里得做
p指的是字符变到0-26之后的值
p=k*26+k1*x+k2
所以k1*x+k*26=p-k2
令k1=a,26=b,c=p-k2;
所以就是a*x+b*y=c;
用拓欧解就行
//p=x%26;
//p=k*26+k1*x+k2
//k*26+k1*x=p-k2
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
ll t_gcd(ll a,ll &x,ll b,ll &y){
    if(b==0){
        x=1;y=0;
        return a;
    }
    ll d=t_gcd(b,y,a%b,x);
    y-=a/b*x;
    return d; 
}
ll k1,k2;
char s[maxn];
int main(){
    scanf("%d%d",&k1,&k2);
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i<len;i++){
        ll p;
        if(s[i]>='a'&&s[i]<='z'){
            p=s[i]-'a';
        }
        else{
            p=s[i]-'A'; 
        }
        ll a=k1,x,b=26,y;
        ll d=t_gcd(a,x,b,y);
        x*=(p-k2)/d;
        ll t=b/d;
        
        x=(x%t+t)%t;
        if(s[i]>='a'&&s[i]<='z'){
            printf("%c",x+'a'); 
        }
        else{
            printf("%c",x+'A'); 
        }
    } 
    return 0;
} 

 

 
posted @ 2021-01-18 22:10  哎呦哎(iui)  阅读(104)  评论(0编辑  收藏  举报