Java B组蓝桥杯第八届国赛:小计算器

38 篇文章 1 订阅
32 篇文章 2 订阅

标题:小计算器

模拟程序型计算器,依次输入指令,可能包含的指令有

1. 数字:'NUM X',X为一个只包含大写字母和数字的字符串,表示一个当前进制的数
2. 运算指令:'ADD','SUB','MUL','DIV','MOD',分别表示加减乘,除法取商,除法取余
3. 进制转换指令:'CHANGE K',将当前进制转换为K进制(2≤K≤36)
4. 输出指令:'EQUAL',以当前进制输出结果
5. 重置指令:'CLEAR',清除当前数字

指令按照以下规则给出:
数字,运算指令不会连续给出,进制转换指令,输出指令,重置指令有可能连续给出
运算指令后出现的第一个数字,表示参与运算的数字。且在该运算指令和该数字中间不会出现运算指令和输出指令
重置指令后出现的第一个数字,表示基础值。且在重置指令和第一个数字中间不会出现运算指令和输出指令
进制转换指令可能出现在任何地方

运算过程中中间变量均为非负整数,且小于2^63。
以大写的'A'~'Z'表示10~35

[输入格式]
第1行:1个n,表示指令数量
第2..n+1行:每行给出一条指令。指令序列一定以'CLEAR'作为开始,并且满足指令规则

[输出格式]
依次给出每一次'EQUAL'得到的结果

[样例输入]
7
CLEAR
NUM 1024
CHANGE 2
ADD
NUM 100000
CHANGE 8
EQUAL

[样例输出]
2040

补充说明:
1. n 值范围: 1<= n < 50000
2. 初始默认的进制是十进制

资源约定:
峰值内存消耗 < 256M
CPU消耗  < 1000ms


请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

这也不知道是哪位人才出的题,浪费我一天时间,各种测试,各种找其他博主的代码,(10个代码9个不通过,他们大多就是通过了样例,然后说这个题没啥难度,测试全是运行错误)终于找到一个c++的代码在网站上测试成功之后,开始努力看代码,强行把c++一对一换成java之后,又对比之前的代码找自己的出错的问题,终于测试通过了。(不想承认又不得不承认自己水平很低)

这一届国赛题看贴吧里有各种吐槽的,做个两道多就是国二。我发现这一年的题并不是很难,只是因为出题人语文太好,出的题目逻辑不通,几乎每道题都玩一些文字游戏,完全是看运气,谁能和出题人想到一块,谁就能很容易做出来。

下面说一下这个题目需要注意的地方,也是我疑惑的地方:

(1)题目的NUM指令参数X:“X为一个只包含大写字母和数字的字符串”,是类似“10AB43”这样的数。

由于样例输入也没给出特殊实例,谁能想到是类似“10AB43”这样的数,大写字母和数字掺杂,想想那些参赛的考生做题,还没法测试。没看出来这个点,这题就凉了。(我一开始以为是101B,4654O,329D,51H,类似这样的末尾带进制标识符,因为题目没有规定初始进制状态!!!),(不知道正在看这里的你有没有相同的感受,不会就我自己这么菜吧)

(2)题目的进制转换指令'CHANGE K',(这里又是一个小坑,被我踩进去了),将当前进制转换为k进制。这句话没毛病,值得注意的是,整个程序中用到的进制,是同一个进制,不管是当前主数字的进制,还是运算时另外一个数字的进制,还是输出的进制,全都是一个进制,简单的来讲就是设置一个全局变量int通用就完事了。

(3)如果你已经会了上面两个点,那就可以来看第三个点:那个X,就是又含大写字母又含数字的X,它要参与计算首先得转成数字,那怎么转成数字呢?题目中已经告知了A~Z代表10~36,为了方便说明,我这里用上面提到的一个例子“10AB43”来解释。

正常人的思路会想到直接将A替换成10,B替换成11,得到10101143,看似没毛病,样例输入没有这样的例子,所以程序写成这样样例测试没毛病。

考试的话再一次凉凉,这道题一分没有。因为服务器系统测试里可不会有样例输入。废话好像扯太多了,抱歉,我今天太想吐槽。

哈哈,好了,言归正传,我们来看10AB43怎么换:

正确操作:不管是字符串,还是数字,它们每一个占一位,如果是大写字母对应两位数,但它们的权值是共用的,所以  

          结果 =  值 x  权值

我们从左往右开始分析每一位,为了方便我计算偷懒,咱就先假设当前的进制10进制。

1——>1x1e5=1x100000=100000

0——>0x1e4=0x10000=0

A——>10x1e3=10x1000=10000

B——>11x1e2=11x100=1100

4——>4x1e1=4x10=40

3——>3x1e0=3x1=3

最后加到一起10AB43——>111143,这时候在对比一下直接换字母的结果10101143,#%¥#%@#%¥&(我就问谁能想到........)

那如果你拥有了以上三点,可以来测试如下例子,应该是可以成功的。

蓝桥杯练题系统第一个测试

输入:

23
CLEAR
NUM 281659794
ADD
NUM 1722405514
MOD
NUM 660145688
EQUAL
DIV
NUM 19821154
MUL
NUM 922337202603578091
EQUAL
SUB
CHANGE 31
NUM ABO16DF
SUB
NUM 3LJI76O4
ADD
NUM 25RAC4GA
SUB
NUM IPA0SG0J
MOD
NUM 21Q75TT

输出

23628244
922337202603578091

(4)害,还有最后一点,就是重置命令CLEAR,说的是清除当前数字,就是不存在,是空的,程序里写的话就是不能用它参与下次计算,除非赋予新值。

我这坑又掉进去了,这题专门就适合坑我。如果单纯的将当前数字置0,置-1,那它就会参与下次计算的,然后就乱套了,0分走起......

这里有两个方式处理,在代码注释中解释了很详细,结合之后应该很容易理解。

测试网址:https://www.dotcpp.com/oj/problem1844.html

来看代码:

import java.util.Scanner;

public class Main {
	long num1 = 0;//主要参数
	long num2 = 0;//辅助计算的参数
	int jinzhi = 10;//进制默认10
	int op = 0;//运算操作,用数字代替字符串比较,简化操作,节约开销,不用也行
	public Main() {
		Scanner sn = new Scanner(System.in);
		int n = sn.nextInt();//n次
		//循环处理每条命令
		for (int i = 0; i < n; i++) {
			//把命令变成字符数组,简化字符串比较
			char[] s = sn.next().trim().toCharArray();
			if (s[0] == 'C' && s[1] == 'L') {
				/* 这里需要讲一下,重置指令,题目中描述清除当前的数字,就是不存在了,置空,不要置0或置-1
				 *.因为测试中有个坑,比如:ADD指令后接一个CLEAR
				 *.如果在这里简单的将当前数字置0,整个程序就乱套了,这个0会和一个数进行ADD运算
				 *.显然程序不会报错,但答案不对的
				 *.这里两种方式:一个是你真的把当前数字清除了,就是添加一个变量标记,表示当前数字无法使用
				 *.第二个就是把运算命令清除,显然这个运算命令不参与计算,改成不相关的任意值即可,我这里是置0
				 * */
				op=0;
			} else if (s[0] == 'N') {//给一个数
				//先换成10进制数
				long n1 = change_X_10(jinzhi, sn.next().trim());
				if (op!=0) {
					num2 = n1;// 赋给参与计算的第二个数
					calculate();//计算
				} else {
					num1 = n1;//赋给主要参数
				}
			} else if (s[0] == 'A') {//加
				op = 1;
			} else if (s[0] == 'S') {//减
				op = 2;
			} else if (s[0] == 'M' && s[1] == 'U') {//乘
				op = 3;
			} else if (s[0] == 'D') {//除
				op = 4;
			} else if (s[0] == 'M' && s[1] == 'O') {//余
				op = 5;
			} else if (s[0] == 'C' && s[1] == 'H') {//设置进制
				/*
				 * .可以看到这里只是简单的换了一下进制的参数,而没有对主要参数num1进行转换
				 * .因为对系统测试而言,他只看输出,因此在输出时,转一下进制给机器看。
				 * .对我们自己而言,全部用十进制更方便,不需要模拟进制转换进行计算,用了更麻烦,还没用
				 * 
				 */
				jinzhi = sn.nextInt();
			} else if (s[0] == 'E') {//输出,利用Long自带的进制转换
				System.out.println(Long.toString(num1,jinzhi));
			}
		}
		sn.close();
	}

	//计算
	public void calculate() {
		switch (op) {
		case 1:
			num1 += num2;
			break;
		case 2:
			num1 -= num2;
			break;
		case 3:
			num1 *= num2;
			break;
		case 4:
			num1 /= num2;
			break;
		case 5:
			num1 %= num2;
			break;
		default:
			break;
		}
		op = 0;
	}
/*
 *. 例:10AB43
 * 100000
 * 00000
 * 10000
 * 1100
 * 40
 * 3
 * 111143
 * 
 * */
	//将任意进制转换成10进制
	public long change_X_10(int j, String s) {
		long n1 = 0;
		int l=s.length();
		//遍历每一位
		for (int i = l - 1; i >= 0; i--) {
			long n2 = 1;
			//这里n2用来计算位置获取权值
			for (int k = 1; k <= l- i - 1; k++)
				n2 *= j;
			//这里区分数字和大写字母
			if (s.charAt(i) >= '0' && s.charAt(i) <= '9')
				n1 += n2 * (s.charAt(i) - '0');
			else
				n1 += n2 * (s.charAt(i) - 55);//这里简化计算,原式是('大写字母'-'A'+10),用ASCII值简化
		}
		//返回合成的10进制数
		return n1;
	}


	public static void main(String[] args) {
		new Main();
	}

}

最后来看一下蓝桥杯练习系统和C语言网刷题系统的测试结果对比,一样的代码:

蓝桥杯的:

 

C语言网的:

蓝桥杯显示内存超限,442MB????,在看C语言网的,这个单位应该是KB,16388KB=16MB,于是我在代码里加了测试语句,结果是18兆左右,应该是和C语言网的差不多的,运行时间也是一点就会给出答案,耗时不长,感觉和C语言网的更符合,那么问题就来了?蓝桥杯的练题系统还要VIP,就这服务器这.......,所以不建议蓝桥杯练题系统,做对了也坑的自己找不到北。或者是vip会有更好的服务器进行测试?????

这里有测试代码内存使用大小的方法:https://blog.csdn.net/qq_43319748/article/details/109538308

 

 

 

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值