按位与运算符"&"是双目运算符是参与运算的两数各对应的二进位相与。
按位与"&"功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1 ,否则为0。参与运算的数以补码方式出现。
例如:9&5可写算式如下: 00001001 (9的二进制补码)&00000101 (5的二进制补码)
00001001
00000101
对比2个数的补码可以得出结构为 00000001 也就是1的二进制补码
可见9&5=1。 按位与运算通常用来对某些位清0或保留某些位。
当然通过一道题 我发现了 &与字母顺序有关的题 有着十分便利的妙用。
题目描述
16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法 Vigenère 密码。Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为南军所广泛使用。
在密码学中,我们称需要加密的信息为明文,用 MM 表示;称加密后的信息为密文,用 CC 表示;而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为 kk。 在 Vigenère 密码中,密钥 kk 是一个字母串,k=k_1,k_2,…,k_nk=k1,k2,…,kn。当明文 M=m_1,m_2,…,m_nM=m1,m2,…,mn 时,得到的密文 C=c_1,c_2,…,c_nC=c1,c2,…,cn,其中 c_ici=m_imi®k_iki,运算®的规则如下表所示:
Vigenère 加密在操作时需要注意:
-
®运算忽略参与运算的字母的大小写,并保持字母在明文 MM 中的大小写形式;
-
当明文 MM 的长度大于密钥 kk 的长度时,将密钥 kk 重复使用。
例如,明文 M=Helloworld,密钥k=abc 时,密文 C=Hfnlpyosnd。
输入格式
共 2 行。
第一行为一个字符串,表示密钥 kk,长度不超过 100,其中仅包含大小写字母。
第二行为一个字符串,表示经加密后的密文,长度不超过 1000,其中仅包含大小写字母。
输出格式
一个字符串,表示输入密钥和密文所对应的明文。
输入输出样例
输入 #1复制
CompleteVictory Yvqgpxaimmklongnzfwpvxmniytm
输出 #1复制
Wherethereisawillthereisaway
按照题目所说也好理解 只需要先弄出秘钥字母的位子 再用密文给的字母减去秘钥的位子就可以得到明文。
那么首先我们可以先需要3个数组存放密文 秘钥 明文;
然后测出密文和秘钥的长度 ,由于秘钥基本都比密文短 还需要拼接,
cin>>k>>s;
len1 = strlen(k);//测出密钥长度
len2 = strlen(s);//密文长度
if (len1 < len2)
for (int i = len1; i < len2; i++) k[i] = k[i - len1];
来看核心部分
首先是大小写问题 特判即可,再者明文是密文的字母减去秘钥字母得到的。所以会出现减到a一下的情况需要额外分类。只需要加上26就行了。
for (int i = len1; i < len2; i++) k[i] = k[i - len1]; for (int i = 0, j; i < len2; i++)
{
if (k[i] >= 'A' && k[i] <= 'Z') j = k[i] - 'A';
if (k[i] >= 'a' && k[i] <= 'z') j = k[i] - 'a';
ans[i] = s[i] - j;
if (s[i] >= 'A' && s[i] <= 'Z')
if (ans[i] < 'A') ans[i] += 26;
if (s[i] >= 'a' && s[i] <= 'z')
if (ans[i] < 'a') ans[i] += 26;
}
完整的代码是
#include<bits/stdc++.h>
char k[1010], s[1010], ans[1010];
int len1, len2;
int main()
{
cin >> k >> s;
len1 = strlen(k);//测出密钥长度
len2 = strlen(s);//密文长度
if (len1 < len2)
for (int i = len1; i < len2; i++) k[i] = k[i - len1];
for (int i = 0, j; i < len2; i++)
{
if (k[i] >= 'A' && k[i] <= 'Z') j = k[i] - 'A';
if (k[i] >= 'a' && k[i] <= 'z') j = k[i] - 'a';
ans[i] = s[i] - j;
if (s[i] >= 'A' && s[i] <= 'Z')
if (ans[i] < 'A') ans[i] += 26;
if (s[i] >= 'a' && s[i] <= 'z')
if (ans[i] < 'a') ans[i] += 26;
}
for (int i = 0; i < len2; i++) printf("%c", ans[i]);/
return 0;
}
是不是很长。我去看了其他大佬的解题方法,发现了一种十分简单的代码 及时使用了&的运算
再发简易之前我们先来看点东西
0100 0001 | 65 | 41 | A |
0100 0010 | 66 | 42 | B |
0100 0011 | 67 | 43 | C |
0100 0100 | 68 | 44 | D |
0100 0101 | 69 | 45 | E |
0100 0110 | 70 | 46 | F |
0100 0111 | 71 | 47 | G |
0100 1000 | 72 | 48 | H |
0100 1001 | 73 | 49 | I |
0100 1010 | 74 | 4A | J |
0100 1011 | 75 | 4B | K |
0100 1100 | 76 | 4C | L |
0100 1101 | 77 | 4D | M |
0100 1110 | 78 | 4E | N |
0100 1111 | 79 | 4F | O |
0101 0000 | 80 | 50 | P |
0101 0001 | 81 | 51 | Q |
0101 0010 | 82 | 52 | R |
0101 0011 | 83 | 53 | S |
0101 0100 | 84 | 54 | T |
0101 0101 | 85 | 55 | U |
0101 0110 | 86 | 56 | V |
0101 0111 | 87 | 57 | W |
0101 1000 | 88 | 58 | X |
0101 1001 | 89 | 59 | Y |
0101 1010 | 90 | 5A | Z |
0110 0001 | 97 | 61 | a |
0110 0010 | 98 | 62 | b |
0110 0011 | 99 | 63 | c |
0110 0100 | 100 | 64 | d |
0110 0101 | 101 | 65 | e |
0110 0110 | 102 | 66 | f |
0110 0111 | 103 | 67 | g |
0110 1000 | 104 | 68 | h |
0110 1001 | 105 | 69 | i |
0110 1010 | 106 | 6A | j |
0110 1011 | 107 | 6B | k |
0110 1100 | 108 | 6C | l |
0110 1101 | 109 | 6D | m |
0110 1110 | 110 | 6E | n |
0110 1111 | 111 | 6F | o |
0111 0000 | 112 | 70 | p |
0111 0001 | 113 | 71 | q |
0111 0010 | 114 | 72 | r |
0111 0011 | 115 | 73 | s |
0111 0100 | 116 | 74 | t |
0111 0101 | 117 | 75 | u |
0111 0110 | 118 | 76 | v |
0111 0111 | 119 | 77 | w |
0111 1000 | 120 | 78 | x |
0111 1001 | 121 | 79 | y |
0111 1010 | 122 | 7A | z |
直接看对应的字母a的二进制代码 A的二进制码
0110 0001 0100 0001
x 跟X
0111 1000 0101 1000
可以看到 相同字母的后5位二进制是相同的。
而且用对应字母&31(11111)得到的就是改字母在字母表中的顺序
例如a&31
0110 0001
0001 1111
0000 0001
也就是a&31=1(0000 0001)
大写的由于后5位相同也是同理
利用这个性质
我们就只需要考虑边界值问题即可
#include<bits/stdc++.h>
using namespace std;
int main() {
string k, c;
cin >> k >> c;
for (int i = 0; i < c.length(); i++) {
int t = (k[i % k.length()] & 31) - 1;
c[i] = (c[i] & 31) - t > 0 ? c[i] - t : c[i] - t + 26;
}
cout << c << endl;
return 0;
}
叶jq