[雅礼中学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 正确200.01
2 正确200.01
3 正确200.01
4 正确200.01
5 正确200.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;
}

转载于:https://www.cnblogs.com/klarkxy/archive/2010/10/03/10017168.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值