&运算符的用法

按位与运算符"&"是双目运算符是参与运算的两数各对应的二进位相与。

按位与"&"功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为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​,运算®的规则如下表所示:

扫描二维码关注公众号,回复: 13465167 查看本文章

Vigenère 加密在操作时需要注意:

  1. ®运算忽略参与运算的字母的大小写,并保持字母在明文 MM 中的大小写形式;

  2. 当明文 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

猜你喜欢

转载自blog.csdn.net/zjsru_Beginner/article/details/119947820