Vigenère密码
题目描述
6世纪法国外交家 B l a i s e d e V i g e n e ˋ r e Blaise \space de \space Vigenère Blaise de Vigeneˋre设计了一种多表密码加密算法—— V i g e n e ˋ r e Vigenère Vigeneˋre密码。 V i g e n e ˋ r e Vigenère Vigeneˋre密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用。
在密码学中,我们称需要加密的信息为明文,用
M
M
M表示;称加密后的信息为密文,用
C
C
C
表示;而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为
k
k
k。 在
V
i
g
e
n
e
ˋ
r
e
Vigenère
Vigeneˋre密码中,密钥
k
k
k是一个字母串,
k
=
k
1
k
2
…
k
n
k=k_1k_2…k_n
k=k1k2…kn。当明文
M
=
m
1
m
2
…
m
n
M=m_1m_2…m_n
M=m1m2…mn时,得到的密文
C
=
c
1
c
2
…
c
n
C=c_1c_2…c_n
C=c1c2…cn,其中
c
i
=
m
i
®
k
i
c_i=m_i®k_i
ci=miR◯ki,运算
®
®
R◯的规则如下表所示:
Vigenère加密在操作时需要注意:
1.
®
®
R◯运算忽略参与运算的字母的大小写,并保持字母在明文
M
M
M中的大小写形式;
2.当明文
M
M
M的长度大于密钥
k
k
k的长度时,将密钥
k
k
k重复使用。
例如,明文 M M M= H e l l o w o r l d Helloworld Helloworld,密钥 k k k= a b c abc abc时,密文 C C C= H f n l p y o s n d Hfnlpyosnd Hfnlpyosnd。
输入格式
第一行为一个字符串,表示密钥k
,长度不超过100
,其中仅包含大小写字母。
第二行为一个字符串,表示经加密后的密文,长度不超过1000
,其中仅包含大小写字母
对于100%的数据,输入的密钥的长度不超过100
,输入的密文的长度不超过1000
,且都仅包含英文字母。
输出格式
输出共1行,一个字符串,表示输入密钥和密文所对应的明文。
输入输出样例
输入 #1
CompleteVictory
Yvqgpxaimmklongnzfwpvxmniytm
输出 #1
Wherethereisawillthereisaway
1.题意解析
这是一道很经典的字符串模拟问题,类似的题还有[GESP202306 三级] 密码合规。反正我是被卡了好久。
根据上面运算
®
®
R◯的规则表,我们可以发现,将A~Z
(这里暂时使用大写,后面的代码中使用小写)映射为距离A
的距离。比如A
可以映射为1
,F
可以映射为5
,Z
可以映射为25
,ch
就可以映射为ch-'a'
。
那么
A
®
B
(
这里的
A
和
B
均为字符变量
)
A ® B(这里的A和B均为字符变量)
AR◯B(这里的A和B均为字符变量)就相当于起始为A-'a'
的循环字符串的B-'a'+1
个字符。
然后再逆推就可以得到求明文 M M M的公式
(密文的映射-密钥的映射+26)%26+‘a’
转换成代码就是:(c_i-k_i+26)%26+'a'
注意,c_i有可能会小于k_i,在减之后我们加上一个26就能确保映射的正确。
还要解决几个问题:
1.题目要求忽略大小写,保留在 M M M中的大小写。
先将秘钥 k k k全部转换为小写,在遍历 M M M时判断 M i M_i Mi的大小写形式。是大写就先按小写转换,最后再转换成大写。
2.秘钥 k k k重复利用
只需要取个模就行了。具体事例请看代码。
2.AC代码
#include<bits/stdc++.h>
using namespace std;
bool is_big(char c)//判断是否是大写字母
{
return c>='A'&&c<='Z';
}
string btos(string s)//字符串大写转小写函数
{
for(int i=0;i<s.length();i++)
if(is_big(s[i]))
s[i]+='a'-'A';
return s;
}
int main()
{
string k,C,M;
cin>>k>>C;
k=btos(k);//秘钥忽略大小写,直接全部转小写
for(int i=0;i<C.length();i++)//遍历字符串
{
char ch;
if(is_big(C[i]))//如果是大写字母
{
C[i]+='a'-'A';//先转小写
//计算当前字符距离a的差距
int k_i=k[i%k.length()]-'a',c_i=C[i]-'a';
ch=(c_i-k_i+26)%26+'a';//映射寻找M_i
ch-='a'-'A';//再转回大写
}
else
{
//计算当前字符距离a的差距
int k_i=k[i%k.length()]-'a',c_i=C[i]-'a';
ch=(c_i-k_i+26)%26+'a';//映射寻找M_i
}
M+=ch;
}
cout<<M;
return 0;
}
喜欢就订阅此专辑吧!
【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。
欢迎扫码关注蓝胖子编程教育