【题解】【模拟】—— Vigenère密码

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=k1k2kn。当明文 M = m 1 m 2 … m n M=m_1m_2…m_n M=m1m2mn时,得到的密文 C = c 1 c 2 … c n C=c_1c_2…c_n C=c1c2cn,其中 c i = m i ® k i c_i=m_i®k_i ci=miRki,运算 ® ® 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可以映射为1F可以映射为5Z可以映射为25ch就可以映射为ch-'a'

    那么 A ® B ( 这里的 A 和 B 均为字符变量 ) A ® B(这里的A和B均为字符变量) ARB(这里的AB均为字符变量)就相当于起始为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;
}

喜欢就订阅此专辑吧!

【蓝胖子编程教育简介】
蓝胖子编程教育,是一家面向青少年的编程教育平台。平台为全国青少年提供最专业的编程教育服务,包括提供最新最详细的编程相关资讯、最专业的竞赛指导、最合理的课程规划等。本平台利用趣味性和互动性强的教学方式,旨在激发孩子们对编程的兴趣,培养他们的逻辑思维能力和创造力,让孩子们在轻松愉快的氛围中掌握编程知识,为未来科技人才的培养奠定坚实基础。

欢迎扫码关注蓝胖子编程教育
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝胖子教编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值