蓝桥杯历届试题 小计算器题解

问题描述

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


  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'得到的结果

题解:蓝桥杯果然还是以模拟为主吗。。而且题目让我难免想起当年被中缀表达式折磨的痛苦经历orz。还好这道题没有那么过分。按照题干的描述,我们要存储一个数并在特定的进制下对它完成计算要求,而且还要实现初始化。由于进制的存在,输入和输出变得很麻烦。我为了方便,决定把数字全部转化为10进制,这样计算任务就没有难度了,但是我们要重写一个输入和输出。具体过程详见代码。

#include <iostream>
#include <cstdio>
#include <string>
using namespace std;
long long read(int);
void put(long long, int);
int main()
{
    ios::sync_with_stdio(false);//加速cin和cout 实测能加速60ms左右
    int n;
    cin >> n;
    long long num1 = 0, num2 = 0;//因为数据范围要求一定要用long long
    bool bo = 0;//if CLEAR
    int j = 10;//j进制 虽然题干没说但是显然初始值应该是10
    for(int _=1;_<=n;_++)
    {
        string s;
        cin >> s;
        int taps;
        if(s[0] == 'C' && s[1] == 'L')bo = 0;//CLEAR
        if(s[0] == 'N')//NUM
        {
            if(bo)
            {
                num2 = read(j);
                if(taps == 1)num1 += num2;
                if(taps == 2)num1 -= num2;
                if(taps == 3)num1 *= num2;
                if(taps == 4)num1 /= num2;
                if(taps == 5)num1 %= num2;
            }
            else 
            {
                num1 = read(j);
                bo = 1;
            }
        }
        if(s[0] == 'A')taps = 1;//ADD
        if(s[0] == 'S')taps = 2;//SUB
        if(s[0] == 'M' && s[1] == 'U')taps = 3;//MUL
        if(s[0] == 'D')taps = 4;//DIV
        if(s[0] == 'M' && s[1] == 'O')taps = 5;//MOD
        if(s[0] == 'C' && s[1] == 'H')cin >> j;//CHANGE
        if(s[0] == 'E')//EQUAL
        {
            put(num1, j);
            cout << endl;
        }
        
    }
    return 0;
}
long long read(int j)//读入一个j进制的数并把它转换成10进制
{
    string s;
    long long num = 0;
    cin >> s;
    int l = s.length();
    /********
     * 以下为转换过程 设一个j进制数x的第i位数字为x[i]
     * 则10进制下x为sum(x[i]*j^i-1)
     *******/
    for(int i = l-1;i >= 0;i--)
    {
        long long num1 = 1;
        for(int k = 1; k <= l - i - 1; k++)num1 *= j;
        if(s[i] >= '0' && s[i] <= '9')num += num1 * (s[i]- '0');
        else num += num1 * (s[i] - 55);//该位为字母时,字符ascii码-55即可
    }
    return num;
}
void put(long long num, int j)//将10进制数字num转化为j进制输出 模拟短除法
{
    if(num < j)//无法继续短除则停止计算,输出并回溯
    {
        if(num < 10)cout << num;
        else cout << (char)(num +55);//十分烦人的字母orz
        return;//回溯
    }
    int num1 = num % j;
    long long num2 = num /j;
    put(num2, j);
    if(num1 < 10)cout << num1;
    else cout << (char)(num1 +55);//十分烦人的字母*2
    return;
}

没有思维难度但是很考验代码水平 这道题很值得练习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值