Vigenère 解密即逐位模 26 减法 m = (c − k) mod 26,负数加 26 归正,密钥循环复用,大小写沿用密文。
OJ: roj
题目 ID: 3598
难度:普及-
标签:模拟字符串数学python
创建: 2026-10-02 09:52
更新: 2026-10-07 13:50
前置题目
noi_openjudge ch0107-09密码翻译A 教的「字母平移后字母表回绕」这一步被 B 的解密公式逐位复用,只是把固定 +1 换成密钥位偏移并补上 i % len(key) 密钥循环与大小写跟随密文luogu P1914小书童——凯撒密码B 把 A 教的字母数值化后取模 26 平移,直接扩成逐位 (c − k) % 26 的逆运算,并叠加 i % len(key) 密钥循环与大小写保持noi_openjudge ch0107-10简单密码B 把 A 教的“字母转下标后减去偏移、%26 再转回字符”直接用作逐位解密,只是把固定偏移 5 换成密钥字母并叠加 i%len(key) 循环。
题目描述
给定密钥串 CompleteVictory / Yvqgpxaimmklongnzfwpvxmniytm,样例输出 Wherethereisawillthereisaway。
思路
加密是逐位模 26 加法,解密就是逐位模 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-10-02 09:53
# update_at: 2026-10-02 09:53
import sys
def undo(ch: str, kch: str) -> str:
"""® 运算的逆:明文字母 = 密文字母 − 密钥字母(mod 26),忽略大小写、大小写取自密文。"""
plain = (ord(ch.lower()) - ord(kch.lower())) % 26 # 明文在字母表中的序号 A=0
return chr(plain + ord('A' if ch.isupper() else 'a'))
def solve() -> None:
lines = [ln.strip() for ln in sys.stdin.read().splitlines() if ln.strip()]
key = lines[0] # 密钥,长度 ≤ 100,只有字母
cipher = lines[1] # 密文,长度 ≤ 1000;密钥不足时循环重复使用
# 逐位用密钥对应字母解密一个字母,密钥下标 i % len(key) 即"重复使用"的落点
print(''.join(undo(ch, key[i % len(key)]) for i, ch 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-06 14:55
* update_at: 2026-10-06 14:55
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
string key; // 密钥串,长度不超过 100,仅含字母
string cipher; // 密文串,长度不超过 1000,仅含字母,密钥不足时循环使用
// 求单个密文字母的明文:按密文自身大小写解码,'A'/'a' 为 0
char decode_char(char c, char k) {
int cv = tolower(c) - 'a'; // 密文数值
int kv = tolower(k) - 'a'; // 密钥数值
int mv = (cv - kv + 26) % 26; // 模 26 减法,负数加 26 回到 [0,26)
char base = isupper(c) ? 'A' : 'a'; // 大小写沿用密文
char plain_char = base + mv;
return plain_char;
}
int main() {
cin >> key >> cipher;
ll n = key.size();
ll m = cipher.size();
string plain;
// 逐位解密,密钥下标 i % n 实现密钥循环重复使用
for (ll i = 0; i < m; i++) {
plain += decode_char(cipher[i], key[i % n]);
}
cout << plain << endl;
return 0;
}
