week 1 模拟与高精度

训练第一周,一共给我们做了三道题:乒乓球,高精度加法和高精度累加求和。

由于乒乓球那道题一开始漏加条件了...所以先做的高精度加法然后再回头做的乒乓球。

总体做下来给我的感觉就是,按照题目要求模拟还是挺简单的,但是真正把代码写出来并且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,第一周的练习带给了我很多的收获。这也是我第一次写博客,肯定有很多不足的地方,我会在未来不断改进。

感谢阅读。

附:最后一题中开头的数组定义应该放到全局而不是主函数里,可能会造成内存爆炸的情况。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无用夜宵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值