[雅礼中学2005分区联赛模拟试题]编码
[题目]
编码(Encode.pas/exe)
【问题描述】
DEX国刚刚截获了KCAJ国与AWAW国之间的S.Message[1]。D国S302情报机构情报员007[2]手里正拿着写有K国与A国之间Message的文件。“什么?!居然被加密了!!”007忍不住说道,“KCAJ,你会出路的!”
幸运的是K国与A国此次通讯时间远远超过了007所估计的30s,因此007又截获了大量的Message。通过对这些Message的研究,007发现了其中的秘密:
每一条S.Message原本由8个32-bit的正整数N1..N8组成,本来这8个整数可以由计算机直接破解得出相应的文字。但对于每条信息,K国与A国另外使用了不同的密钥M来再次加密。所谓“密钥”其实也是一个32-bit的整数,在传递讯息的时候,是将N1 Xor M、N2 Xor M、…、N8 Xor M、N9 Xor M这9个整数传给对方(其中N9为N1~N8这8个整数的和Mod 2^32)。
有了上面的发现,007马上意识到他可以破解出Message了!这实在是一个简单的工作,007决定让你——也就是他的助手来完成此工作。
【输入】
输入文件按顺序输入9个整数N1..N9。每个整数用16进制表示。
【输出】
输出仅一个数,即密钥M。同样用16进制表示。
【样例输入】
3 4 4 7 7 b a 2 2e
【样例输出】
6
【数据范围】
40%的数据满足M<=500;
100%的数据满足M<2^32;
[1] S.Message是Seceret Message的缩写,绝对不是Short Message的缩写
[2] 此人极度神秘,目前只知道他的代号为302.007
[成绩]
标题:编码 | |||
文件名:encode.cpp | |||
编号 | 结果 | 得分 | 有效用时 |
1 | 正确 | 20 | 0.01 |
2 | 正确 | 20 | 0.01 |
3 | 正确 | 20 | 0.01 |
4 | 正确 | 20 | 0.01 |
5 | 正确 | 20 | 0.01 |
总分:100 | |||
有效用时:0.05 |
[报告]
通过搜索构造,能成功解出这道题目,不过Tony_____(两个希腊字母,打不出来)用数位DP做出来了。不过对于数位DP,真的不懂,我只能做的就是搜索。
先把所有的数从16进制转换成2进制,然后从最低位开始构造。对于每位(设是第I位,这里是从低位开始的第I位,如个位是第1位)的构造,先填0,若填0后最后I位不符合要求,就填1——PS,二进制数每一位不填0就填1。
这个符合要求的处理时核心的。鄙人的方法非常简陋——每次判断都重新计算一遍(因为如果每次不重新算,就是WA的),看计算出来的结果。
至此,该题目已成功解决——虽然有更好的方法。
[程序](程序比较复杂,有很多废话)
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <string>
#define N 50
using namespace std;
ifstream fin ("encode.in");
ofstream fout ("encode.out");
char n[10][N+1];
static inline void make(char
ch,char&a,char&b,char&c,char&d)
{
a=b=c=d=0;
switch (ch)
{
case 'f':a=1;
case '7':b=1;
case '3':c=1;
case '1':d=1;break;
case 'e':a=1;
case '6':b=1;
case '2':c=1;
case '0':break;
case 'd':a=1;
case '5':b=1;d=1;break;
case 'c':a=1;
case '4':b=1;break;
case
'b':a=1;c=1;d=1;break;
case 'a':a=1;c=1;break;
case '9':a=1;d=1;break;
case '8':a=1;break;
}
}
static inline void change(char n[],string s)
{
for (long
i=s.length()-1,j=N-3;i>=0;i--,j-=4)
make(s[i],n[j],n[j+1],n[j+2],n[j+3]);
}
static inline void ouot(char n[],long q=0)
{
long i=0;
while
(i<N-q&&n[i]==0)
i++;
for (;i<=N;i++)
cout
<< long(n[i]);
cout << endl;
}
char m[N+1];
string ans;
char
al[16]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
static inline char chtu(char a,char b,char c,char d)
{
long q=0;
if (a) q+=8;
if (b) q+=4;
if (c) q+=2;
if (d) q+=1;
return al[q];
}
static inline string turn(char m[])
{
string ret;
ret.clear();
for (long j=N-3;j>=0;j-=4)
while
(ret.length()>1&&ret[0]=='0')
ret.erase(0,1);
return ret;
}
char ls[N+1];
static inline bool ok(long
d)
// 第D位能否放0
{
memset(ls,0,sizeof(ls));
for (long j=0;j<=N;j++)
for (long
i=1;i<=8;i++)
if
(n[i][j]!=m[j])
ls[j]++;
for (long j=N;j>0;j--)
{
ls[j-1]+=ls[j]/2;
ls[j]%=2;
}
for (long j=N;j>0;j--)
if (ls[j]!=m[j])
ls[j]=1;
else ls[j]=0;
return (ls[d]==n[9][d]);
}
int main(int argc, char *argv[])
{
memset(n,0,sizeof(n));
for (long i=1;i<=9;i++)
{
string s;
fin
>> s;
change(n[i],s);
}
long c=0;
memset(m,0,sizeof(m));
for (long i=N;i>0;i--)
{
long q=c;
for (long
j=1;j<=8;j++)
q=q+n[j][i];
if (ok(i)) m[i]=0;
else m[i]=1;
c=q/2;
}
ans=turn(m);
fout << ans
<< endl;
return
EXIT_SUCCESS;
}