题解:P1079 [NOIP2012 提高组] Vigenère 密码

· · 题解

传送门。

题目分析:

\ 观察图片我们可以发现密钥每往后移一位整个字母表就往前移一位。所以我们可以得出一个公式 m_i-(k_i-A)=c_i。当然,这里的 k_i 为大写字母。\ 可是我们还会发现一个问题:如果 m_iA(k_i-A) \ne 0 时,再按刚刚的式子来算的结果就不是字母了。所以,我们要分类讨论即当 m_i-(k_i-A) < A 时答案就为 Z-(A-(m_i-(k_i-A))+1。当 m_i 为小写字母时只需将 Z-(A-(m_i-(k_i-A))+1 改为 z-(a-(m_i-(k_i-A)))+1 即可。

分析完了,那该怎么实现呢?\ 这里给出代码:

#include<bits/stdc++.h>
using namespace std;
string m,k;
int sum=0;
char s;//为当前字母的密文。
int main(){
    cin>>k>>m;
    for(int i=0;i<k.size();i++)if(k[i]>='a'&&k[i]<='z')k[i]-=32;//将密钥统一转化为大写字母,这样好算些。
    for(int i=0;i<m.size();i++){
        if(m[i]>='A'&&m[i]<='Z'){//分类讨论,当明文为大写字母时。
            if(m[i]-(k[sum]-'A')>='A'&&m[i]-(k[sum]-'A')<='Z')s=m[i]-(k[sum]-'A');//还记得公式吗?
            else s=char('Z'-('A'-(m[i]-(k[sum]-'A')))+1);
        }
        else{//当明文为小写字母时。
            if(m[i]-(k[sum]-'A')<='z'&&m[i]-(k[sum]-'A')>='a')s=m[i]-(k[sum]-'A');
            else s=char('z'-('a'-(m[i]-(k[sum]-'A')))+1);
        }
        cout<<s;//输出密文。
        sum++;//密钥往后移一位。
        if(sum==k.size()){//判断:当密钥移到最后一位时就从头开始。
            sum=0;
        }
    }
    return 0;//华丽结束。
}

我的 AC 记录,未吸氧。