训练的第一周,就三题,乒乓球模拟,高精度加法,高精度求累加和。
对于乒乓球模拟,我在想没打过乒乓球可能真的写不出来
国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。
其中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:121: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完成了欸