题解:洛谷 B4500 凯撒密码

【题目来源】

洛谷:B4500 [GESP202603 三级] 凯撒密码 - 洛谷

【题目描述】

凯撒密码是一种替换加密技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是 \(3\) 的时候,所有的字母 \(A\) 将被替换成 \(D\)\(B\) 被替换成 \(E\)\(C\) 被替换成 \(F\),以此类推,\(W\) 被替换成 \(Z\)\(X\) 被替换成 \(A\)\(Y\) 被替换成 \(B\)\(Z\) 被替换成 \(C\)。这个加密方法是以罗马共和时期凯撒的名字命名的,据称当年凯撒曾用此方法与其将军们进行联系。

但是和所有的利用字母表进行替换的加密技术一样,凯撒密码非常容易被破解,而且在实际应用中也无法保证通信安全。

现在给你一个已破解的凯撒密码明文与密文,与一个有相同偏移量的未破解凯撒密码密文,请你帮忙破解它。

【输入】

输入共三行:

第一行包含一个字符串,表示已破解的凯撒密码明文;

第二行包含一个字符串,表示已破解的凯撒密码密文;

第三行包含一个字符串,表示待破解的凯撒密码密文。

【输出】

输出一行,包含一个字符串,表示待破解的凯撒密码对应的明文。

【输入样例】

ABCDEFGVWXYZ
DEFGHIJYZABC
WKHTXLFNEURZQIRAMXPSVRYHUWKHODCBGRJ

【输出样例】

THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG

【核心思想】

  1. 问题分析:给定一组已破解的凯撒密码明文和密文,先从中提取偏移量 \(\delta\),再用该偏移量解密另一段密文。凯撒密码的本质是固定偏移的字母循环替换,加密时每个字母向后偏移 \(\delta\) 位,解密时向前偏移 \(\delta\) 位(或向后偏移 \(26 - \delta\) 位)。

  2. 算法选择

    • 偏移量提取:利用已知明文-密文对的首字符差值确定偏移量 \(\delta = b[0] - a[0]\)
    • 模运算解密:将字符映射到 \(0 \sim 25\) 的数值域,执行模 \(26\) 的减法运算后再映射回字符
  3. 关键步骤

    • 读取输入:明文 \(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\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(|c|)\),与待解密字符串长度成线性关系
    • 空间复杂度:\(O(1)\)(除输入字符串外),原地修改待解密串
  5. 凯撒密码解密的核心思想

    • 模运算循环性:字母表共 \(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
posted @ 2026-07-01 21:38  团爸讲算法  阅读(34)  评论(0)    收藏  举报