解密(拓展欧几里的)
链接: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
输出描述:
输出一行字符串,为解密后的字符串
备注:
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; }