题目链接
这道题不难,但是对用分段思路的人来说,非常非常坑爹,应该有不少人和我一样,认为自己写的代码和《算法笔记》上面几乎没有区别,但是有两个评测点通过不了,即测试点2(第三个测试点)和测试点5(最后一个测试点)。
长话短说,以下:
测试点2的数据:
数字B的位数小于数字A的位数:
例如:A=123456 B=789
正确输出:927Q32
错误输出:123Q32
测试点5的数据:
数字B的位数小于数字A的位数,而且数字A前面有0.
例如: A=000456 B=789
正确输出:000Q32
错误输出::0:Q32
其中冒号:的ASCII码是58
以下是分析过程:
《算法笔记》上的参考代码:
#include <cstdio>
#include <cstring>
const int maxn=110;
char A[maxn],B[maxn],ans[maxn]={0};
void reverse(char s[]){
int len=strlen(s);
for (int i=0; i<len/2; i++){
int temp=s[i];
s[i]=s[len-1-i];
s[len-1-i]=temp;
}
}
int main(){
scanf("%s %s",A,B);
reverse(A);
reverse(B);
int lenA=strlen(A),lenB=strlen(B);
int len=lenA>lenB?lenA:lenB;
for (int i=0; i<len; i++){
int numA=i<lenA?A[i]-'0':0;
int numB=i<lenB?B[i]-'0':0;
if (i%2==0){
int temp=(numA+numB)%13;
if (temp==10) ans[i]='J';
else if (temp==11) ans[i]='Q';
else if (temp==12) ans[i]='K';
else ans[i]=temp+'0';
}else {
int temp=numB-numA;
if (temp<0) temp+=10;
ans[i]=temp+'0';
}
}
reverse(ans);
puts(ans);
}
注意他的循环是for (int i=0; i<len; i++),从头到尾,没有分段。
我的两个测试点都通过不了得代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
char a[110],b[110],c[110];
scanf("%s %s",a,b);
char str[]="0123456789JQK";
int lenA=strlen(a),lenB=strlen(b);
for (int i=1; i<=min(lenA,lenB); i++ ){
if (i%2==1){
c[i]=str[(a[lenA-i]-48+b[lenB-i]-48)%13];
}else {
int temp=b[lenB-i]-a[lenA-i];
c[i]=temp<0?temp+10+48:temp+48;
}
}
for (int i=min(lenA,lenB)+1; i<=max(lenA,lenB); i++){
c[i]=i<=lenA?a[lenA-i]:b[lenB-i];
}
for (int i=max(lenA,lenB); i>=1; i--) putchar(c[i]);
}
我是分段循环,感觉和书上的代码差别不大,但是两个测试点都通过不了,仔细比对了我和书上的代码,分析出错是在第二段循环:
for (int i=min(lenA,lenB)+1; i<=max(lenA,lenB); i++){
c[i]=i<=lenA?a[lenA-i]:b[lenB-i];
}
这里是有问题的,这就是测试点2,出错的原因,例如123456和789,我认为456和789进行运算得到Q32以后,A的位数多,前面的123直接输出就可以了,结果就是123Q32,但是正确结果是927Q32,因为789实际上是000789,A前面的123会和B的000运算,只有2保留,1会变成0-1+10=9,3会变成0-3+10=7;
我意识到这个问题,以后,把第二段循环改成这个样子:
for (int i=min(lenA,lenB)+1; i<=max(lenA,lenB); i++){
if (i&1) c[i]=i<=lenA?a[lenA-i]:b[lenB-i];
else c[i]=i<=lenB?b[lenB-i]:-(a[lenA-i]-48)+10+48;
}
然而出乎意料的是测试点2通过了,测试点5还是通过不了,百思不得其解,最后觉得唯一的可能出错的地方就是0.
例如000456和789运算,789会变成000789,那么按照我这个朴素的思路,对前面的000和000运算,0-0+10=10,最后ASCII就是10+48=58,也就是冒号:,最后就输出了:0:Q32,而我想输出000Q32。
所以我又把这个第二段循环改成:
for (int i=min(lenA,lenB)+1; i<=max(lenA,lenB); i++){
if (i&1){
c[i]=i<=lenA?a[lenA-i]:b[lenB-i];
}
else {
if (i<=lenB){
c[i]=b[lenB-i];
}else {
int temp=0-(a[lenA-i]-48)+10+48;
c[i]=temp==58?48:temp;
}
}
}
这次所有测试点都通过了,但是代码改的也太麻烦了,事实上这些代码没啥用处,这题用分段写容易出错,之所以我要不断修改这个代码,是因为我特别想知道到底分段代码哪里有问题,在第一次出错以后,我试着只用一个循环来进行运算,这个代码就很简洁,只有20行:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main(){
char a[110],b[110],c[110];
scanf("%s %s",a,b);
char str[]="0123456789JQK";
int lenA=strlen(a),lenB=strlen(b);
for (int i=1; i<=max(lenA,lenB); i++ ){
int numA=i<=lenA?a[lenA-i]-'0':0;
int numB=i<=lenB?b[lenB-i]-'0':0;
if (i%2==1){
c[i]=str[(numA+numB)%13];
}else {
int temp=numB-numA;
c[i]=temp<0?temp+10+48:temp+48;
}
}
for (int i=max(lenA,lenB); i>=1; i--) putchar(c[i]);
}
没有用《算法笔记》上面的反转之类的函数,因为觉得没有必要,小题大做,循环里面也没有JQK之类的判断,直接用一个数组就可以搞定。
这题测试数据很坑爹,题目讲的不清楚,很多人哪里会想到123456和789运算,789还要补零成000789,按照很多人思路,既然789前面什么都没,那么结果的前三位直接就是123了。