第一周 模拟与高精度

  训练的第一周,就三题,乒乓球模拟,高精度加法,高精度求累加和。

对于乒乓球模拟,我在想没打过乒乓球可能真的写不出来

国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。

其中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分制下的结果,两部分之间由一个空行分隔。

输入样例:

WWWWWWWWWWWWWWWWWWWW
WWLWE

输出样例: 

11:0
11:0
1:1

21:0
2:1

先解释一下乒乓球的11分制与21分制是什么

一局11分制比赛中,先得11分的运动员为胜方,但打到10平以后,先多得2分者为胜方 

21分制一样,先得21分的运动员为胜方,打到20平后,先多得2分者为胜方

拿11分制为例子   条件出来了 自己得分为win 对方得分为lose

win==11且lose<=9(我赢了且没达到十平碾压对面)

或lose==11且win<=9(我输了被对面碾压了)

或win>10,lose>10 且|win-lose|=2;

整合一下就是((win>=11 || lose>=11)&&abs(win-lose)>=2)

打印输出完记得重置win 与 lose

输入方式可以用字符串或者字符数组

代码如下

#include <bits/stdc++.h>
using namespace std;
int main(){
    string s,a="a";
    int win=0,lose=0;
    while(cin>>s){
      int n=s.length();
      for(int i=0;i<n;i++){
          if(s[i]=='E'){
          	printf("%d:%d\n\n",win,lose);
          	win=0;
          	lose=0;
          	break;
		  }
          else if(s[i]=='W') win++;
          else if(s[i]=='L') lose++;
          if((win>=11||lose>=11)&&abs(win-lose)>=2){
              printf("%d:%d\n",win,lose);
              win=0;
              lose=0;
          }
      }
      a=a+s;
      if(n<20){
        int m=a.length();
        for(int i=1;i<m;i++){
    	    if(a[i]=='E'){
          	  printf("%d:%d",win,lose);
          	  win=0;
          	  lose=0;
           	  break;
		    }
       		else if(a[i]=='W') win++;
       		else if(a[i]=='L') lose++;
       		if((win>=21||lose>=21)&& abs(win-lose)>=2){
                printf("%d:%d\n",win,lose);
                win=0;
                lose=0;
            }        	
	    }
	    a="a";
	  }
    }
}

乒乓球模拟只要懂得了比赛规则就比较简单

下一题高精度加法

典型的a+b类型题

对于输入的两个不超过100位数字的非负整数,给出两数之和。

输入格式:

在两行中分别给出两个不超过100位数字的非负整数

输出格式:

在一行中输出两数之和

输入样例:

123

12

输出样例: 

135 

 仔细想一下,题目要求我们进行一百位数字的加法运算,但是c++里面最大的也就2^64不足100位

那我们要进行100位数字的加法运算要怎么实现呢?

1234567890是一个十位数字,一百位数字用数据类型储存不了,但是却可以用数组储存轻松储存

int a[100];一个100位的a数组

所以,我们可以用字符数组或者字符串来储存输入的数组string s;cin>>s;

接着实现相加的步骤

看例子123 和12按照小学学的加法计算方式

应该为   1  2  3

       +         1  2

------------------------------

      =      1  3   5

要相对应的个位加上个位;十位加上十位,就得逆序相加

或者:我们可以把数组输入时 “逆序输入”来让相加看的更加直白

a=321 b=21 for循环相加就可以更加简便地实现a+b

在对十进制进行研究 如12 和 9 个位相加等于11 个位留1,进位为1;

个位就等于11%10,进位就等于11/10

再进入下一个数位的相加

#include <bits/stdc++.h>
using namespace std;
int main(){
    string n,m,t,x;
    int f[101];
    memset(f,0,sizeof(f));//把f数组赋值为0也可以把f[101]定义在主函数外面
    cin>>n>>m;//输入要相加的两串数字
    int a=n.length();
    int b=m.length();
    t=a>b?n:m;//得出较长数字串
    x=a>b?m:n;
    int c,d;
    int c1=0;
	c=max(a,b);//c为较长的数组长度
	d=min(a,b);//d为较短的数组长度
	int e=d;
    for(int i=c-1;i>=c-d;i--){//二者相加的部分的长度就是较短的那个数组x的长度d
    	f[i+1]=(t[i]+x[i-c+d]-'0'-'0'+c1)%10;//用数字字符串逆序相加,对f数组使用逆序输入
    	c1=(t[i]+x[i-c+d]-'0'-'0'+c1)/10;//c1进位 
    }
   	for(int i=c-d-1;i>=0;i--){//相加完后可能会有进位到下一个数位
	   f[i+1]=(t[i]-'0'+c1)%10;//所以我们循环后面的数组去对下一个数位进行判断
   	   c1=(t[i]-'0'+c1)/10;
	}
	f[0]=c1;//c1表示进位,可能有进位也可能没有进位
	if(f[0]!=0){//c1不等于0说明产生了t里面的数与x相加后有进位,t的长度应该就比原来长1
	  for(int i=0;i<c+1;i++){
	  	  cout<<f[i];
	  }
	  cout<<endl;
	}
	else{//c1等于0,没有产生进位,t的长度不变
	  for(int i=1;i<c+1;i++){
	    cout<<f[i];
	  }
	  cout<<endl;
    }
}

 

第三题 高精度累加求和

使用求和公式求1到N的累加和大家都会,但是如果把N值变大呢,比如100位的整数,那该怎么求?

输入格式:

输入在一行中给出1个位数不超过100位的整数N。

输出格式:

对每一组输入,在一行中输出1+2+3+……+N的值。

输入样例:

在这里给出一组输入。例如:

10

输出样例: 

在这里给出相应的输出。例如:

55

 我们上面刚写完加法,这里要求我们进行累加求和,

我们不可能输入一个数每次减一在相加过程太麻烦了

那我们把10的累加求和写出来看看

10的累加求和1+2+3+...+9+10=55

有没有一种熟悉的感觉  小学学过的高斯求和得出 (1+10)*10/2=55;

所以在这边我们得对输入的数字n先进行+1操作,再让n*(n+1)再/2 

那我们下面来看看用数组模拟高精度乘法的实现

10*11,小学是这样实现的

        1   0

x      1   1

-----------------

        1   0      (1x10)

+ 1   0   0     (10x10)

-----------------------------

=  1   1   0

如上所示就让11的个位与十位分别与10相乘然后相加

int a[n];长度为n的数组a 或者位数为n的数字a

int b[m];长度为m的数组b 位数为m的数字b

int c[n+m];二者相乘长度一定小于等于m+n

再把a,b,c数组全部初始化为0或者把他们定义在主函数外面

利用双层for循环实现a与b的乘法

for(int i=0;i<n;i++){

     for(int j=0;j<m;j++){

           c[i+j]+=a[i]*b[j];

           c[i+j+1]+=c[i+j]/10;

           c[i+j]%=10;

       }

}

依旧拿10x11来做例子

a[0]=0,a[1]=1;长度为2

b[0]=1.b[1]=1;长度为2

i=0;j=0时c[0]+=a[0]*b[0] 此时c[0]为0;

i=0;j=1时c[1]+=a[0]*b[1] 此时c[1]为0;

i=1;j=0时c[1]+=a[1]*b[0] 此时c[1]为1;

i=1;j=1时c[2]+=a[1]*b[1] 此时c[2]为1;

再输出c为110它的长度为3

换一组数据 用一组用得上jinwei的数据更能体现

66*19

a[0]=6,a[1]=6;

b[0]=9;b[1]=1;逆序输入

i=0;j=0时c[0]+=6*9此时c[0]=54 c[0]=4,c[1]=5

i=0;j=1时c[1]+=(6*1)此时c[1]=11,c[1]=1,c[2]=1

i=1;j=0时c[1]+=(6*9)此时c[1]=55, c[1]=5,c[2]=6

i=1;j=1时c[2]+=(6*1)此时c[2]=12,c[2]=2,c[3]=1;

此时输出c为1254长度为4

高精度乘法得出后

除以2的模拟就很简单了

看这个数位上的数是不是2的倍数,是的话直接对2整除,不是的话先对2 整除然后下一位加上10再对2整除

高精度求累加和的代码如下

#include <bits/stdc++.h>
using namespace std;
int a[202],b[202],c[202];
int main(){
	string s;
    cin>>s;
	int n=s.size();
	for(int i=0;i<n;i++){
		a[n-i]=s[i]-'0';
		b[n-i]=s[i]-'0';
	}
	b[1]++;//实现n+1
	for(int i=1;i<n;i++){
		if(b[i]==10){
			b[i]=0;
			b[i+1]++;
		}
		else break;
	}
	for(int i=1;i<=n;i++){//实现高精度乘法
		for(int j=1;j<=n;j++){
			c[i+j-1]+=a[j]*b[i];
			c[i+j]+=c[i+j-1]/10;
			c[i+j-1]%=10;
		}
	}
	int gs=2*n;
	for(int i=gs;i>=1;i--){//实现除以2
		if(c[i]%2==0){
			c[i]/=2;
		}
		else{
			c[i-1]+=10;
			c[i]/=2;
		}
	}
	while(c[gs]==0&&gs>1) gs--;//输出结果
	 for(int i=gs;i>=1;i--){
		cout<<c[i];
	 }
}

我的第一篇blog完成了欸

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值