- gf24240 的博客
《梦溪笔谈·C++》卷三十六:加密训练Ⅳ
- 2025-9-13 14:03:22 @
前言
以前的加密都是映射关系,只要得到了表格就好了。
无聊的说明
这是某个时间想到的(可能是在集训或者上课的时候吧,只有这两个时间最无聊)。
对要加密的字符的 ASCII 调整会怎么样?
其实一开始想的是交换位数,但是很多字符会神秘消失。因为 ASCII 有的是一位数,有的是三位数,不好调整。
于是就想到了格雷码 。其实我还没学这个,但是从 DP 了解到,计算 x
的格雷码的方法是 x ^ (x >> 1)
。
于是就开始写代码了(此处为伪代码):
while get(c):
c = c ^ (c >> 1);
put(c);
但是这有一些问题: ASCII 有些字符看不见 ,也打不出来。这些是要跳过的字符。
我整理了一些空的字符,在代码的 wit
函数里了。可以看到的空格也是要跳过的。
所以有了下面的伪代码:
while get(c):
c = c ^ (c >> 1);
while !check(c):
c = c ^ (c >> 1);
put(c);
但是我希望保留空格。但是这里还是有问题:如果要加密一句话,每个字符 Gary 的次数不同,所以无法解码。
根据我发现的性质:每个字符编码一定次数后都会返回到原字符。 所以才有了上面的一条问题。如果一个句子每个字符编码次数不同,就不能编码多次后解码。
所以,每次检查句子,如果有一个字符空,那么就再给每个字符都编码一次。就是下面的代码了。
#include <iostream>
using namespace std;
bool wit(char c)
{
return (c <= 32 || c == 127);
}
bool cse(string s)
{
for (char ch : s)
{
if (ch == ' ')continue;
if (wit(ch))return 0;
}
return 1;
}
string gary(string s)
{
for (char& ch : s)
{
if (ch == ' ')continue;
ch = ch ^ (ch >> 1);
}
return s;
}
int main()
{
string s;
while ((getline(cin, s)))
{
s = gary(s);
while (!cse(s))
{
s = gary(s);
}
cout << s << "\n";
}
return 0;
}