当前位置: 代码迷 >> 综合 >> 2020 CCPC Wannafly Winter Camp Day1 Div.12——密码学【构造 模拟】
  详细解决方案

2020 CCPC Wannafly Winter Camp Day1 Div.12——密码学【构造 模拟】

热度:20   发布时间:2023-12-16 22:56:08.0

题目传送门


题目描述

考虑一种加密方式,它需要一个任意长度的原文 {m}m 和秘钥 {key}key,其中要求原文和秘钥只包含大写和小写的英文字符。
首先定义字符之间的加密,用字符 a a a 去加密字符 b b b 的结果是:

  • 首先把 a a a b b b 转成数字 x x x y y y。转换的规则是,小写字母 a a a z z z 依次对应 0 0 0 25 25 25,大写字母依次对应 26 26 26 51 51 51
  • 计算 x x x y y y 的和 z z z,对 52 52 52 取模,即计算 ( x + y ) m o d 52 (x+y) \bmod 52 (x+y)mod52
  • 返回数字 z z z 对应的字符。

现在来讲如何用秘钥 k e y key key 来加密原文 m m m

  • 如果秘钥的 k e y key key 的长度小于 m m m,那么不停重复 k e y key key 直到长度不小于 m m m 为止。举例来说,如果原文是 b e i j i n g beijing beijing,秘钥是 P K U S A A PKUSAA PKUSAA,那么秘钥需要被重复称 P K U S A A P K U S A A PKUSAAPKUSAA PKUSAAPKUSAA
  • 假设原文的长度是 n n n,那么对于每一个 [ 1 , n ] [1,n] [1,n] 的数字 i i i,都用 k e y key key 的第 i i i 个字符去加密 m m m 的第 i i i 个字符。
  • 返回结果。

那么用 P K U S A A PKUSAA PKUSAA 去加密 b e i j i n g beijing beijing 的结果就是: Q O c b I N V QOcbINV QOcbINV
现在火山哥有 n n n 个字符串, s 1 s_1 s1? s n s_n sn?,他对这些字符串做了 m m m 次加密操作:第 i i i 次加密操作用第 s ? x i s_{?x_i} s?xi?? 去加密 s ? y i s_{?y_i} s?yi??,并把 s ? y i s_{?yi} s?yi? 替换成加密结果。
现在依次给出 m m m 次加密操作,以及加密操作结束后每一个字符串的模样,你可以还原出这 n n n 个字符串原来的模样吗?


输入描述:

第一行输入两个整数 n , m n,m n,m ( 1 ≤ n , m ≤ 1000 ) ( 1 ≤ n , m ≤ 1000 ) (1\leq n,m\leq 1000)(1≤n,m≤1000) (1n,m1000)(1n,m1000)
接下来 m m m 行每行输入两个整数 x i , y i x_i,y_i xi?,yi?,表示依次加密操作,保证 x i x_i xi? 不等于 y i y_i yi?
接下来 n n n 行每行输入一个字符串,表示加密最后的结果。字符串的长度在 1 1 1 100 100 100 之间,只包含大小写英文字符。


输出描述:

输出 n n n 行,每行一个字符串,表示原本的字符串。


输入

2 1
1 2
PKUSAA
QOcbINV


输出

PKUSAA
beijing


题解

  • easy
  • 题面中给出了已知原文和秘钥,加密得到密文的方法。其实已知密文和秘钥,就可以轻松的解密出原文:只要用密文对应的数字减去秘钥对应的数字就可以了。
    因此,我们可以从后往前“撤销”所有加密操作带来的影响。假设最后一次加密操作是用 s x s_x sx? 去加密 s y s_y sy?,那么在结果中, s x s_x sx? 是没有发生变化的,即秘钥已知; s y s_y sy?,存储的是结果,即密文已知。从而用上面的方法可以直接从两者之中推出 s y s_y sy?,原来的值。
  • 所以从后往前考虑每一次加密操作,依次进行撤销,最后得到的就是最开始的 nn 个字符串。

AC-Code

#include <bits/stdc++.h>
using namespace std;int xi[1005], yi[1005];
string str[1005];
int f1(char c) {
     return c > 'Z' ? c - 'a' : c - 'A' + 26; }
char f2(int x) {
     return x >= 26 ? 'A' + x - 26 : 'a' + x; }
void sub(char& s1, char& s2) {
    s2 = f2((f1(s2) - f1(s1) + 52) % 52);
}
void solve(int a, int b) {
    for (int i = 0, j = 0; str[b][j]; ++i, ++j) {
    if (!str[a][i])i = 0;sub(str[a][i], str[b][j]);}
}
int main() {
    int n, m;while (cin >> n >> m) {
    for (int i = 0; i < m; ++i) cin >> xi[i] >> yi[i];for (int i = 1; i <= n; ++i) cin >> str[i];for (int i = m - 1; i >= 0; --i) solve(xi[i], yi[i]);for (int i = 1; i <= n; ++i) cout << str[i] << endl;}return 0;
}