题解:洛谷 B4500 凯撒密码
【题目来源】
洛谷:B4500 [GESP202603 三级] 凯撒密码 - 洛谷
【题目描述】
凯撒密码是一种替换加密技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是 \(3\) 的时候,所有的字母 \(A\) 将被替换成 \(D\),\(B\) 被替换成 \(E\),\(C\) 被替换成 \(F\),以此类推,\(W\) 被替换成 \(Z\),\(X\) 被替换成 \(A\),\(Y\) 被替换成 \(B\),\(Z\) 被替换成 \(C\)。这个加密方法是以罗马共和时期凯撒的名字命名的,据称当年凯撒曾用此方法与其将军们进行联系。
但是和所有的利用字母表进行替换的加密技术一样,凯撒密码非常容易被破解,而且在实际应用中也无法保证通信安全。
现在给你一个已破解的凯撒密码明文与密文,与一个有相同偏移量的未破解凯撒密码密文,请你帮忙破解它。
【输入】
输入共三行:
第一行包含一个字符串,表示已破解的凯撒密码明文;
第二行包含一个字符串,表示已破解的凯撒密码密文;
第三行包含一个字符串,表示待破解的凯撒密码密文。
【输出】
输出一行,包含一个字符串,表示待破解的凯撒密码对应的明文。
【输入样例】
ABCDEFGVWXYZ
DEFGHIJYZABC
WKHTXLFNEURZQIRAMXPSVRYHUWKHODCBGRJ
【输出样例】
THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG
【核心思想】
-
问题分析:给定一组已破解的凯撒密码明文和密文,先从中提取偏移量 \(\delta\),再用该偏移量解密另一段密文。凯撒密码的本质是固定偏移的字母循环替换,加密时每个字母向后偏移 \(\delta\) 位,解密时向前偏移 \(\delta\) 位(或向后偏移 \(26 - \delta\) 位)。
-
算法选择:
- 偏移量提取:利用已知明文-密文对的首字符差值确定偏移量 \(\delta = b[0] - a[0]\)
- 模运算解密:将字符映射到 \(0 \sim 25\) 的数值域,执行模 \(26\) 的减法运算后再映射回字符
-
关键步骤:
- 读取输入:明文 \(a\)、密文 \(b\)、待解密串 \(c\)
- 计算偏移量:\(\delta = b[0] - a[0]\)(密文字符与明文字符的 ASCII 码差值)
- 逐字符解密:对 \(c\) 的每个字符 \(c_i\):
- 数值化:\(\text{num} = c_i - \texttt{`A'}\)(映射到 \(0 \sim 25\))
- 解密:\(\text{num} = (\text{num} - \delta + 26) \bmod 26\)(向前偏移 \(\delta\) 位,加 \(26\) 防止负数)
- 字符化:\(c_i = \texttt{`A'} + \text{num}\)
- 输出结果:解密后的字符串 \(c\)
-
时间/空间复杂度:
- 时间复杂度:\(O(|c|)\),与待解密字符串长度成线性关系
- 空间复杂度:\(O(1)\)(除输入字符串外),原地修改待解密串
-
凯撒密码解密的核心思想:
- 模运算循环性:字母表共 \(26\) 个字符,偏移操作在模 \(26\) 意义下进行,保证 \(Z\) 偏移 \(1\) 位后回到 \(A\)。公式 \((\text{num} - \delta + 26) \bmod 26\) 中,加 \(26\) 是为了处理负数情况,确保取模结果非负
- 单字符推断全局偏移:凯撒密码对所有字符使用相同的偏移量,因此只需一对已知明文-密文字符即可确定整个密码系统的密钥
- 数值域转换:将字符运算转化为 \(0 \sim 25\) 的整数运算,避免直接处理 ASCII 码的边界问题(如
A减 \(3\) 变成^而非X),使模运算逻辑清晰 - 原地解密:直接在原字符串上修改,无需额外空间,体现了字符串处理的高效性
- 适用于经典替换密码的加解密、循环移位、字符编码转换等基础密码学问题
【算法标签】
入门 #字符串入门
【代码详解】
#include <bits/stdc++.h>
using namespace std;
string a, b, c; // 定义三个字符串:a(明文1), b(密文1), c(要解密的字符串)
int main() // 主函数入口
{
// 输入:a是已知明文,b是已知密文,c是要解密的密文
cin >> a >> b >> c;
// 计算加密位移量:b[0]和a[0]的ASCII码差值
int delta = b[0] - a[0];
// 遍历要解密的字符串c的每个字符
for (int i = 0; i < c.size(); i++)
{
int num = c[i] - 'A'; // 将字符转换为0-25的数字
// 进行解密计算:减去位移量,然后取模26确保在0-25范围内
num = (num - delta + 26) % 26;
c[i] = 'A' + num; // 将数字转换回字符
}
// 输出解密后的字符串
cout << c << endl;
return 0; // 程序正常结束
}
【运行结果】
ABCDEFGVWXYZ
DEFGHIJYZABC
WKHTXLFNEURZQIRAMXPSVRYHUWKHODCBGRJ
THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG
浙公网安备 33010602011771号