Skip to content

E28674:《黑神话:悟空》之加密

implementation, strings, http://cs101.openjudge.cn/pctbook/E28674/

2024年8 月 20 日,广大玩家期待已久的中国首款“3A游戏”《黑神话:悟空》如期发售。游戏内容改编自中国四大名著之一的《西游记》,在正式发布前,游戏已获得业界媒体与评论家们的普遍好评,称赞其在战斗系统、视觉设计以及世界观方面的构建。游戏上线后迅速登顶多个平台的销量榜首,两周内的全球销量超过1800万份,成为有史以来销售速度最快的游戏之一。

你的朋友小xu注意到《黑神话:悟空》至今没有盗版,她感到很好奇,在网上查询后得知《黑神话:悟空》采用“D加密”技术来为防盗版提供技术支持。D加密,全称 Denuvo Anti-Tamper,是由奥地利 Denuvo 公司推出的一种防篡改技术。Denuvo Anti-Tamper 的目标是保护游戏免受盗版和破解攻击。它的原理是在游戏程序中嵌入一些特殊的代码,这些代码会进行复杂的加密和解密操作,使得黑客无法轻易地破解游戏并且在游戏中进行修改。

小xu了解后很感兴趣,于是她开始学习了加密解密相关的技术。某一天,她猜测某一段密文只是采用了一种非常简单的加密方法完成加密:每个字母对应的密文是其在字母表中的后 k 个字母,但 'a' 被视为 'z' 的下一个字母,从而整个字母表形成一个环。例如,如果 k=3,那么字母 'a' 将被加密为 'd','z' 加密为 'c',依此类推。

现在,请你帮助她按照她的猜测完成对密文的破译(即根据密文得出其对应的明文)。

输入

第一行为一个整数 k,表示加密方法中的偏移量。(1 ≤ k ≤ 108000) 第二行为一个由字母组成的字符串 s,表示需要解密的文本。(1 ≤ |s| ≤ 342)

输出

密文对应的明文。

样例输入

sample1 input:
5
LfrjXhnjshj

sample1 output:
GameScience

样例输出

sample2 input:
33
IshjrTfaoDbrvun

sample2 output:
BlackMythWukong

提示

tags: implementation, strings

来源

2024 TA-lxy

【靳熙恒 25 物理学院】初始化的字母表本来是手打的,学了ASCII码,于是可以自动生成字母表了,解放双手!之后还学到可以用 string 库生成字母表。

python
characters = [chr(i) for i in range(65, 91)]
uporlow = []
outstring = ''

k = int(input()) % 26
instring = input()

for i in instring:
    if i.isupper():
        uporlow.append(1)
    if i.islower():
        uporlow.append(0)
instring = instring.upper()

for i in range(len(instring)):
    place = characters.index(instring[i]) - k
    if uporlow[i] == 0:
        outstring += characters[place].lower()
    if uporlow[i] == 1:
        outstring += characters[place]

print(outstring)

思路:

  1. maketrans 是「建规则」:定义 “每个加密字母对应哪个解密字母”;
  2. translate 是「用规则」:把密文中的字母按规则替换,非字母不变。
python
import string

k = int(input())
s = input()  # 原始密文

# 计算解密偏移(等价于向左移动 k 位)
shift = (-k) % 26

# 原始字母表
lower = string.ascii_lowercase  # 'abcdefghijklmnopqrstuvwxyz'
upper = string.ascii_uppercase  # 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

# 构建解密后的字母表:每个字母向前移 k 位
decrypted_lower = lower[shift:] + lower[:shift]
decrypted_upper = upper[shift:] + upper[:shift]

# 创建翻译表:将原字母映射到解密后的字母
translation_table = str.maketrans(lower + upper, decrypted_lower + decrypted_upper)

# 应用翻译并输出
print(s.translate(translation_table))
python
def decrypt_caesar_cipher(k, s):
    decrypted_text = []

    for char in s:
        if 'a' <= char <= 'z':
            decrypted_char = chr((ord(char) - ord('a') - k) % 26 + ord('a'))
        elif 'A' <= char <= 'Z':
            decrypted_char = chr((ord(char) - ord('A') - k) % 26 + ord('A'))
        else:
            decrypted_char = char  # Non-alphabetic characters remain unchanged
        decrypted_text.append(decrypted_char)

    return ''.join(decrypted_text)

# Sample input
k = int(input())
s = input()

# Decrypt and print the result
print(decrypt_caesar_cipher(k, s))

Python 取模运算的核心规则

Python 的取模运算 % 和整除运算 // 遵循以下数学关系:

被除数 = (被除数 // 除数) * 除数 + (被除数 % 除数)

即:a = (a // b) * b + (a % b)

关键在于,Python 的 // 运算符执行的是向下取整除法(floor division),也就是结果向负无穷方向取整。


计算步骤:-1 % 26

我们按照公式来一步步推导:

  1. 计算整除部分 //-1 // 26

    • -1 除以 26 等于 -0.03846...
    • 向下取整(向负无穷方向)是 -1
    • 所以 -1 // 26 = -1
  2. 代入核心公式

    -1 = (-1 // 26) * 26 + (-1 % 26)
    -1 = (-1) * 26 + (-1 % 26)
    -1 = -26 + (-1 % 26)
  3. 求解取模结果

    -1 % 26 = -1 - (-26)
    -1 % 26 = -1 + 26
    -1 % 26 = 25

直观理解

你可以把模运算想象成在“钟表”或“循环”上找位置。

  • 26 就像一个有 26 个刻度的圆盘,编号从 025
  • 0 开始,-1 表示向后退一步。
  • 0 往后退一步,就会到达 25

所以,-1 在模 26 的系统中,等价于 25


为什么这样设计?

这种设计确保了一个非常有用的性质:

当除数(模数)为正数时,取模的结果总是非负的,并且落在 [0, b) 的区间内。

在这个例子中,b = 26,所以 -1 % 26 的结果 25 落在 [0, 26) 区间内。

这在很多场景下非常有用,例如:

  • 数组/列表索引:你想访问一个长度为 26 的列表的最后一个元素,可以用 lst[-1 % 26],它会安全地指向索引 25,而不会产生负索引问题(如果直接用 -1 可能不是你想要的)。
  • 密码学和数学计算:如凯撒密码中,字母移位后需要回绕到字母表开头,使用正的模结果非常方便。

总结

-1 % 26 = 25 是因为:

  1. Python 的 // 是向下取整,-1 // 26 = -1
  2. 代入公式 -1 = (-1) * 26 + x,解得 x = 25
  3. 结果 25 与除数 26 同号(都为正),并且落在 [0, 26) 的理想范围内。

这是 Python 取模运算的标准且一致的行为。