题目描述

Vigenère 密码用密钥串 kk 加密明文:密文第 ii 位 ci=mi⊛ki mod nc_i = m_i \circledast k_{i \bmod n},⊛\circledast 就是题面那张 26×2626 \times 26 的表(密钥位当行、明文字母当列),运算忽略大小写但保留明文字母的大小写;明文比密钥长时密钥循环使用。给定密钥和密文,求明文。

输入两行:第一行密钥 kk(n⩽100n \leqslant 100),第二行密文 CC(m⩽1000m \leqslant 1000),都只含英文字母;输出一行明文。样例输入 CompleteVictory、Yvqgpxaimmklongnzfwpvxmniytm,样例输出 Wherethereisawillthereisaway。

思路

  • 加密是 ci=(mi+ki mod n) mod 26c_i = (m_i + k_{i \bmod n}) \bmod 26,那张表只是把模 26 加法画了出来;解密移项得 mi=(ci−ki mod n) mod 26m_i = (c_i - k_{i \bmod n}) \bmod 26,每位 O(1)O(1),不必建表。
  • 密钥第 ii 位取 ki mod nk_{i \bmod n},明文大小写跟随密文:算出序号后加回密文同款的 'a' 或 'A'。
  • 易错点:相减可能为负(如 6−15=−96-15=-9),模 26 应回绕成 1717;C++ 的 % 保留负号,需手动再 +26。

参考代码

Python 版:

python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 08:51
# update_at: 2026-10-04 10:27

import sys

LOWER = ord('a')  # 小写字母折算 0..25 的基准
UPPER = ord('A')  # 大写字母基准:解出的明文大小写跟随密文字符


def plain_char(c: str, k: str) -> str:
    """解密一个字符:明文序号 = (密文序号 - 密钥位偏移) mod 26,大小写跟随密文。"""
    shift = ord(k.lower()) - LOWER  # 密钥位折算成 0..25 的加密偏移
    base = LOWER if c.islower() else UPPER
    return chr((ord(c) - base - shift) % 26 + base)


def solve() -> None:
    data = iter(sys.stdin.buffer.read().decode().split())  # 按空白顺序切 token:先密钥后密文
    key = next(data)
    cipher = next(data)
    klen = len(key)
    print(''.join(plain_char(c, key[i % klen]) for i, c in enumerate(cipher)))


if __name__ == "__main__":
    solve()

C++ 版(同一算法):

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-10-05 12:53
 * update_at: 2026-10-05 12:53
 */
#include <cstdio>
#include <cstring>
#include <cctype>

using namespace std;

typedef long long ll;

const int MAXN = 1005;

char key_s[MAXN];    // 密钥串,长度不超过 100
char cipher_s[MAXN]; // 密文串,长度不超过 1000
char plain_s[MAXN];  // 解出的明文

int main() {
    scanf("%s", key_s);
    scanf("%s", cipher_s);

    ll n = strlen(key_s);
    ll m = strlen(cipher_s);

    for (ll i = 0; i < m; i++) {
        // 密钥位统一按小写折算成 0..25 的偏移量,运算忽略大小写
        ll shift = tolower(key_s[i % n]) - 'a';
        // 明文大小写跟随密文:基准字符取 'a' 或 'A'
        char base = islower(cipher_s[i]) ? 'a' : 'A';
        // 解密为模 26 减法;C++ 的 % 会保留负号,所以再加一次 26 回绕
        ll idx = (cipher_s[i] - base - shift) % 26;
        if (idx < 0) {
            idx = idx + 26;
        }
        plain_s[i] = base + idx;
    }
    plain_s[m] = '\0';

    printf("%s\n", plain_s);
    return 0;
}