网教23. 暗算 2.0

背景

此“暗算”非彼《暗算》 ;-) ,虽然我们没有电影中阿柄惊人的听力,可以辨别破译密码,但是我们也可以成为破译专家。

现在就来给大家作一个集训:

改变阿拉伯字母的顺序是文本加密中十分常用的方法,但是并不安全。也就是说,把文本中的每一个阿拉伯字母都要一致地替换成一些其他的字母。为了保证加密的可逆性,需要每个阿拉伯字母都有唯一一个替换的字母(也就说,任意两个阿拉伯字母都不可以用同一个字母来替换)。

最有效的密码分析方法就是“已知明文攻击(known-plaintext attack)”法。在此种方法中,密钥专家掌握着敌方加密的短语或语句,然后通过观察这些加密文字从而推导出译码的方法。

你现在的任务就是来破译几行加密的文本,这些文本是用一条密钥加密的,即某一行加密前就是密钥本身。密钥是一个包含了全部 26 个英文字母的字符串,譬如在“暗算 1.0”中,使用的密钥是:

 the quick brown fox jumps over the lazy dog 

不过一个固定的密钥实在是太容易破译了,只要掌握了规律,就不太费劲。为了能够保证信息的安全性,我们决定在此次集训中,使用可变化的密钥。也就是说,每一组测试用例,都包含着自己的密钥。

输入

首先是单独一个正整数用来说明测试的组数,后边跟着一行字符串,这行字符串就是这次测试用例所使用的密钥。再接着是一个空白行。而且,连续两组测试之间也有一个空白行。

每组测试有多行输入组成。加密的方式如上所示。加密的文本行只包含有小写字母和空格,而且长度不超过 200 个字符。最多有 100 条输入的文本行。

输出

对应每组测试, 解密每一行的信息,并且把标准输出打印出来。如果有多于一种的解密方法,那么任何一种都可以。如果没有解密的方法,则输出信息“No solution.”

每两组测试输出之间必须用一个空白行分隔开。

来源

http://online-judge.uva.es/p/v8/850.html

  测试输入关于“测试输入”的帮助 期待的输出关于“期待的输出”的帮助 时间限制关于“时间限制”的帮助 内存限制关于“内存限制”的帮助 额外进程关于“{$a} 个额外进程”的帮助
测试用例 1 以文本方式显示
  1. 1↵
  2. the quick brown fox jumps over the lazy dog↵
  3. vtz ud xnm xugm itr pyy jttk gmv xt otgm xt xnm puk ti xnm fprxq↵
  4. xnm ceuob lrtzv ita hegfd tsmr xnm ypwq ktj↵
  5. frtjrpgguvj otvxmdxd prm iev prmvx xnmq↵
以文本方式显示
  1. now is the time for all good men to come to the aid of the party↵
  2. the quick brown fox jumps over the lazy dog↵
  3. programming contests are fun arent they↵
1秒 1024KB 0
(你直接都说出来了是uva850题……)
题解:
一开始刚看题是一脸懵逼……已知明文攻击是啥意思?后来才知道。。这个题的意思(思路)是先给出一个字符串(密钥),然后再给你几个莫名其妙的字符串,让这些莫名其妙的字符串和已知的密钥相匹配,如果能组成对应关系(空格能对的上,而且26个字母也能一一对应),那么这就是一种解密方法。
题目有一点歧义(导致一开始交题的人只有一个人过,后来多亏煮夫发帖),大家以为是每组都有一次密钥的输入,煮夫发帖之后才知道密钥只有一个,输完num之后输入这次输入里唯一的密钥,其他的东西就只有密文和空行了……
思路比较简单明了,但是注意的细节貌似很多(对3个对4个对5个对6个的版本都有,莫名其妙),虽然我也忘了我从第一版改到最后一版到底改了多少遍……但是我觉得主要要注意的就是空行的读取和输出了吧,然后就是一个数组存读入的所有字符串,一个数组存解密方法,一个数组存密钥,然后注意一下对应关系再输出就好了……我也不知道为啥总是莫名其妙错好几遍,应该就是细节上的问题了,希望其他的做题人注意一下。
AC代码:
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
char str[201];  
char buf[101][201];  
char mask[2][30];     
int  num, len, i;  
int flag;  
int main()  
{  
//  freopen("F:in.txt", "r", stdin);  
//  freopen("F:out.txt", "w", stdout);  
    scanf("%d", &num);  
    getchar();   
    gets(str);//取密钥  
    getchar();//取空行  
    while (num--)  
    {  
        int index = 0;  
  
        len = strlen(str);  
          
        flag = 1;  
        while (1)// 在密文中寻找密钥  
        {  
            int p;  
            if (gets(buf[index]) == NULL)  
                break;  
            if (strlen(buf[index]) ==0)// 遇到空白行,还没找到密钥  
                break;  
              
            if (len == strlen(buf[index])&&flag)  
            {     
                p = 0;  
                for (int t = 0; t < 26; t++)  
                    mask[0][t] = '0';  
                for (i=0; i<len; i++)  
                {  
                    if (str[i] == ' ')  
                    {  
                        if (buf[index][i] == ' ')  
                            continue;  
                        else  
                            break;  
                    }  
                    if (buf[index][i] == ' ')  
                        break;  
                    if (mask[0][buf[index][i] - 'a'] == '0')  
                    {  
                        mask[0][buf[index][i] - 'a'] ++;  
                        mask[1][buf[index][i] - 'a'] = str[i];  
                        p++;  
                    }  
                    else if (mask[1][buf[index][i] - 'a'] != str[i])//不符合已知的规律,就是错的。  
                            break;  
                }  
            }  
            if (str[i] == '\0')  
            {  
                int k, t;  
                for (i = 0; i<25; i++)  
                for (t = i + 1; t<26; t++)  
                if (mask[1][i] == mask[1][t])  
                    break;  
                if (i == 25 && t == 26) flag = 0;  
            }  
            index++;  
        }  
          
        if (flag)  
        {  
            printf("No solution.\n");  
            if (num!=0)  
                printf("\n");  
            continue;  
        }  
  
        for (int k = 0; k < index;k++)//解密  
        {  
            len = strlen(buf[k]);  
            for (int t = 0; t < len; t++)  
            {  
                if (buf[k][t] != ' ')  
                    printf("%c", mask[1][buf[k][t] - 'a']);  
                else   
                    printf("%c", buf[k][t]);  
            }  
            printf("\n");  
        }  
        if (num != 0)  
            printf("\n");  
    }  
    return 0;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值