2016.8.30.第40套测试题
Problems
1. 潜伏者
(spy.pas/c/cpp)
【问题描述】
R 国和S 国正陷入战火之中,双方都互派间谍,潜入对方内部,伺机行动。
历经艰险后,潜伏于S 国的R 国间谍小C 终于摸清了S 国军用密码的编码规则:
1、 S 国军方内部欲发送的原信息经过加密后在网络上发送,原信息的内容
与加密后所的内容均由大写字母‘A’—‘Z’构成(无空格等其他
字母)。
2、 S 国对于每个字母规定了对应的“密字”。加密的过程就是将原信息中
的所有字母替换为其对应的“密字”。
3、 每个字母只对应一个唯一的“密字”,不同的字母对应不同的“密字”。
“密字”可以和原字母相同。
例如,若规定‘A’的密字为‘A’,‘B’的密字为‘C’(其他字母及密字略),则
原信息“ABA”被加密为“ACA”。
现在,小C 通过内线掌握了S 国网络上发送的一条加密信息及其对应的原信息。小C
希望能通过这条信息,破译S 国的军用密码。小C 的破译过程是这样的:扫描原信息,对
于原信息中的字母x(代表任一大写字母),找到其在加密信息中的对应大写字母y,并认
为在密码里y 是x 的密字。如此进行下去直到停止于如下的某个状态:
1、 所有信息扫描完毕,‘A’—‘Z’所有26 个字母在原信息中均出现过
并获得了相应的“密字”。
2、 所有信息扫描完毕,但发现存在某个(或某些)字母在原信息中没有出
现。
3、 扫描中发现掌握的信息里有明显的自相矛盾或错误(违反S 过密码的编
码规则)。例如某条信息“XYZ”被翻译为“ABA”就违反了“不同
字母对应不同密字”的规则。
在小C 忙得头昏脑胀之际,R 国司令部又发来电报,要求他翻译另外一条从S 国刚刚
截取到的加密信息。现在请你帮助小C:通过内线掌握的信息,尝试破译密码。然后利用破
译的密码,翻译电报中的加密信息。
解析:
很简单,就是三个数组,一个记录翻译,两个记录会不会违反规则。
代码:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; char passages[105],keys[105],words[105]; int lp,lk,lw,exchange[30]; bool f1[30],f2[30]; bool flag=false; int main() { freopen("spy.in","r",stdin); freopen("spy.out","w",stdout); cin>>keys>>passages>>words; lp=strlen(passages); lw=strlen(words); for(int i=0;i<lp;i++) { int j=passages[i]-'A'+1; int k=keys[i]-'A'+1; if(f1[j]!=f2[k]||(exchange[k]&&exchange[k]!=j)) { flag=true; break; } exchange[k]=j; f1[j]=f2[k]=true; } for(int i=1;i<=26;i++) if(f1[i]==false) { flag=true; break; } if(flag) { cout<<"Failed"<<endl; return 0; } for(int i=0;i<lw;i++) { int j=words[i]-'A'+1; char t=exchange[j]+'A'-1; cout<<t; } return 0; }
2. Hankson的趣味题
(son.pas/c/cpp)
【问题描述】
Hanks博士是BT(Bio-Tech,生物技术)领域的知名专家,他的儿子名叫Hankson。现在,刚刚放学回家的Hankson正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数c1和c2的最大公约数和最小公倍数。现在Hankson认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:已知正整数a0,a1,b0,b1,设某未知正整数x满足:
1、 x和a0的最大公约数是a1;
2、 x和b0的最小公倍数是b1。
Hankson的“逆问题”就是求出满足条件的正整数x。但稍加思索之后,他发现这样的x并不唯一,甚至可能不存在。因此他转而开始考虑如何求解满足条件的x的个数。请你帮助他编程求解这个问题。
解析:
我最开始用了一个短代码,90,TLE了一个点,然后看大神的代码,发现可以只算根号b1那么多。因为分解b1的因数嘛,相乘肯定一定啊。所以一次性不用全部循环完。结果还是T了一个点,百思不得其解,然后何神一来,看都不看,你用ll肯定挂啊。然后才反应过来int运算比ll快,而一开始为了保险起见,用的ll定义,其实该题是可以用int的。
代码:
#include<iostream> #include<cstring> #include<cstdio> #define ll long long using namespace std; ll a0,a1,b0,b1,a2,b2,s; int n,ans; ll gcd(ll v,ll u) { ll x,y; if(v>u) x=v,y=u; else x=u,y=v; if(y==1) return 1; if(x%y==0) return y; return gcd(y,x%y); } int main() { freopen("son.in","r",stdin); freopen("son.out","w",stdout); cin>>n; for(int i=1;i<=n;i++) { ans=0; cin>>a0>>a1>>b0>>b1;//能被b1整除,能整除a1; a2=a0/a1;//x与 a2 互质 与b0 b2=b1/b0;//x一定有的 a1 b2 s=gcd(a1,b2); s=(a1/s)*b2; for(ll j=s;j<=b1;j+=s) if((gcd(j,a0)==a1) &&((b0/gcd(b0,j)*j)==b1)) { ans++; } cout<<ans<<endl; } return 0; }
解析:
暴搜dfs+几个剪枝
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #define ll long long using namespace std; struct stu{ int x,y,dire; }ans[10]; int n,a; struct st{ int w[10][15]; }map; void down(int v) { if(map.w[v][0]<3) return ; int sum[10]; sum[0]=0; for(int j=1;j<=map.w[v][0];j++) if(map.w[v][j]==map.w[v][j-1]) sum[j]=sum[j-1]+1; else sum[j]=1; for(int j=map.w[v][0];j>=3;) if(sum[j]>=3) { for(int k=j-sum[j]+1;k<=sum[j];k++) map.w[v][k]=map.w[v][k+sum[j]]; map.w[v][0]-=sum[j]; } else j--; } void clean() { for(int i=1;i<=5;i++) down(i); } void dfs(int step) { if(step>n) { for(int i=1;i<=5;i++) if(map.w[i][1]>0) return ; for(int i=1;i<=n;i++) cout<<ans[i].x<<' '<<ans[i].y<<' '<<ans[i].dire<<endl; exit(0); } st ma=map; for(int i=1;i<=5;i++) for(int j=1;j<=map.w[i][0];j++) { if(i<5) { int t=map.w[i+1][j]; map.w[i+1][j]=map.w[i][j]; map.w[i][j]=t; ans[step].x=i-1; ans[step].y=j-1; ans[step].dire=1; clean(); dfs(step+1); map=ma; } if(i>1&&map.w[i-1][j]==0) { int t=map.w[i-1][j]; map.w[i-1][j]=map.w[i][j]; map.w[i][j]=t; ans[step].x=i-1; ans[step].y=j-1; ans[step].dire=-1; clean(); dfs(step+1); map=ma; } } } int main() { freopen("mayan.in","r",stdin); freopen("mayan.out","w",stdout); cin>>n; for(int i=1;i<=5;i++) { int j=0; while(cin>>a&&a) { j++; map.w[i][j]=a; map.w[i][0]=j; } } dfs(1); cout<<"-1"<<endl; return 0; }