训练第一周,一共给我们做了三道题:乒乓球,高精度加法和高精度累加求和。
由于乒乓球那道题一开始漏加条件了...所以先做的高精度加法然后再回头做的乒乓球。
总体做下来给我的感觉就是,按照题目要求模拟还是挺简单的,但是真正把代码写出来并且ac是真的不容易。这些写的很长的代码出了问题全都要debug好久,着实是折磨人。
经过不断的打磨,我悟了。一定要好好写注释!!!
先放出我不成熟的第一题:高精度加法。
题目:
对于输入的两个不超过100位数字的非负整数,给出两数之和。
输入格式:
在两行中分别给出两个不超过100位数字的非负整数
输出格式:
在一行中输出两数之和
下面是代码
#include <bits/stdc++.h>
using namespace std;
int main(){
char a[101]={0}; //错误三
cin.getline(a,101);
//while(getchar()!='\n'){
// continue;
//}
//a[0]='1',a[1]='2',a[2]='2';
char b[101]={0}; //错误三
cin.getline(b,101);
//while(getchar()!='\n'){
// continue;
//}
//b[0]='1',b[1]='2';
int A[100]={0}, B[100]={0}, C[101]={0};
int e=strlen(a);
int f=strlen(b);
for(int i=0;i<e;i++){
A[i]=a[e-i-1]-'0';
}
for(int i1=0;i1<f;i1++){
B[i1]=b[f-i1-1]-'0';
}
int x=0;
if(e>f){
x=e;
}
if(e<=f){
x=f;
}
int q=0;
for(int i2=0;i2<x;i2++){
q=0;
if((A[i2]+B[i2]+C[i2])>9){ //错误一
C[i2]=A[i2]+B[i2]+C[i2]-10;
C[i2+1]++;
q=1; //错误二
}
if((A[i2]+B[i2]+C[i2])<=9&&q==0){ //错误二
C[i2]+=A[i2]+B[i2];
}
}
if(C[x]!=0){
cout<<C[x];
}
for(int k=x-1;k>=0;k--){
cout<<C[k];
}
cout<<endl;
return 0;
}
可以很清晰的看出,这第一道题根本没有注释。coding十分钟,debug二十分钟。
经过两次debug加一段时间的冥思苦想,一共找到三处错误:错误一,原本写的是A[i2]+B[i2]>9的漏加了C[i2];错误二,经过第一个if以后C[i2]已经被改变,故而被改变的C[i2]直接进入了下一个if;错误三,虽说是不超过一百位整数,但是输入的时候还有换行这个玩意没考虑到,于是定义字符串的时候应该多出一位预留空间。
接下来是 h0094乒乓球:
国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。
其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。
华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白11分制和21分制对选手的不同影响。
在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。
华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在11分制和21分制下,双方的比赛结果(截至记录末尾)。
比如现在有这么一份记录,(其中W表示华华获得一分,L表示华华对手获得一分):
WWWWWWWWWWWWWWWWWWWWWWLW
在11分制下,此时比赛的结果是华华第一局11比0获胜,第二局11比0获胜,正在进行第三局,当前比分1比1。
而在21分制下,此时比赛结果是华华第一局21比0获胜,正在进行第二局,比分2比1。
如果一局比赛刚开始,则此时比分为0比0。
你的程序就是要对于一系列比赛信息的输入(WL形式),输出正确的结果。
输入格式:
每个输入文件包含若干行字符串(每行至多20个字母),字符串由大写的W、L和E组成。
其中E表示比赛信息结束,程序应该忽略E之后的所有内容。
输出格式:
输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。
其中第一部分是11分制下的结果,第二部分是21分制下的结果,两部分之间由一个空行分隔。
接下来是代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
//当a>b两分并且a>=11分时,算a赢,反之b赢
char a[1000000];
cin.getline(a,1000000,'E');
// int num1,num2;//记录断点的位置(分别为11分制,21分制)
long long len=strlen(a);
long long A=0,B=0;//记录W,F的个数
//int x1=0;//做判断
for(long long i=0;i<len;i++){
if(a[i]=='W'){
A++;
}
if(a[i]=='L'){
B++;
}
if(((A-B)>1||(B-A>1))&&(A>=11||B>=11)){
cout<<A<<":"<<B<<endl;
A=0;
B=0;
}
if(i==len-1){
cout<<A<<":"<<B<<endl;
}
}
A=0;
B=0;
cout<<endl;
//int x2=0;//做判断
for(long long k=0;k<len;k++){
if(a[k]=='W'){
A++;
}
if(a[k]=='L'){
B++;
}
if(((A-B)>1||(B-A>1))&&(A>=21||B>=21)){
cout<<A<<":"<<B;
A=0;
B=0;
if(k!=len-1){
cout<<endl;
}
}
if(k==len-1){
cout<<A<<":"<<B;
}
}
return 0;
}
可以看到,这道题的注释明显多了起来。但还是前前后后错了好多次,为什么呢?
一开始我debug了很多次,但是都没发现什么问题(也跟这道题不好给样例和测试点有关)。后来实在想不出来了就上网找答案,发现答案的输入格式和我的输入格式不同,所以便认为是我的输入没有严格按照题目要求来。但给我的代码改了输入格式以后发现还是答案错误,这令我十分苦恼。后面又想可能是题目给的数据量太大(毕竟是高精度),于是改了数组的长度,也还是无济于事。最终,经过逻辑推理找到问题所在:
//当a>b两分并且a>=11分时,算a赢,反之b赢
竟然就是这一行注释!
一个“反之”,让我给判定的条件漏了。其实这句话没有逻辑问题。但是在写代码的时候,往前看的太短了,只看到了“a>=11分”,于是便把判定条件写成了
if((A-B)>1)&&(A>=11||B>=11))
if((A-B)>1)&&(A>=21||B>=21))
显然,漏看了前面的“a>b两分”。至此,这道题也终于ac了。
然后就是最后一题了。这道题最难以处理的竟然是思路。对的,你没听错,思路。
题目:
使用求和公式求1到N的累加和大家都会,但是如果把N值变大呢,比如100位的整数,那该怎么求?
输入格式:
输入在一行中给出1个位数不超过100位的整数N。
输出格式:
对每一组输入,在一行中输出1+2+3+……+N的值。
看到高精度累加求和,第一个入脑的肯定是高斯求和公式。这没有错,问题是如何实现。是直接把1和输入的数相加,然后进行高精度乘法,再进行高精度除法?还是把高精度乘法破解为N个(N+1)相加?如果选择破解为相加的话,如何计数?如何存储和调用输入的数和1(毕竟要多次调用此数据,若数据改变,则又要遍历一遍输入的数)?
最后的代码如下:
#include <bits/stdc++.h>
using namespace std;
int main(){
int a[10000],b[10000],c[10000];
string s;
cin>>s;
int x,i,j;
int len=s.size();
for(int i=0;i<len;i++){
a[len-i]=s[i]-'0';
b[len-i]=s[i]-'0';
}
b[1]++;
for(int i=1;i<len;i++){
if(b[i]==10){
b[i]=0;
b[i+1]++;
}
else
break;
}
//到这里已经整理完毕a和b,a=n,b=n+1
//进行高精度乘法n*(n+1)
for(int i=1;i<=len;i++){
x=0;
for(int j=1;j<=len;j++){
c[i+j-1]+=a[j]*b[i]+x;
x=c[i+j-1]/10;
c[i+j-1]%=10;
}
c[i+len]=x;
}
//进行高精度除法
int len2=2*len;
for(int i=len2;i>=1;i--){
if(c[i]%2==0){
c[i]/=2;
}
else{
c[i-1]+=10;
c[i]/=2;
}
}
//判定首部是否为0
while(c[len2]==0&&len2>1){
len2--;
}
//输出
for(int i=len2;i>=1;i--) {
cout<<c[i];
}
return 0;
}
最后代码的注释已经变得更加成熟。有了正确而丝滑的思路及注释,这最后一题反而是最快ac的。
To sum up,第一周的练习带给了我很多的收获。这也是我第一次写博客,肯定有很多不足的地方,我会在未来不断改进。
感谢阅读。
附:最后一题中开头的数组定义应该放到全局而不是主函数里,可能会造成内存爆炸的情况。