题解:B4278 [蓝桥杯青少年组国赛 2023] 简单算术题
wangjue233 · · 题解
Solution
题目解析
这道题给我们一个只包含四则运算符(
- 先算乘除,再算加减;
- 同级运算从左到右;
- 除法只保留整数部分(例如
5 \div 2 = 2 ,忽略小数部分)。
「先乘除后加减」其实是很多运算场景的常识,但平时我们会用括号或者写在不同行来区分运算顺序;本题恰好没给括号,就需要我们自己按照这种顺序来运算。
举个例子:
- 第一步:在整条算式里,先把所有
*
和/
都按从左到右计算一遍:-
3 \times 4 = 12 -
-
-
- 第二步:将上面的结果回填,就得到:
-
2 + 12 - 1 + 0
-
- 第三步:再来一次从左往右进行加减:
-
2 + 12 = 14 -
14 - 1 = 13 -
13 + 0 = 13
-
所以整个表达式的值就是
解题思路
为了实现「先乘除、后加减」,可以把表达式拆分成一段段“连续的乘除块”,然后用加减符号把这些块组合起来:
- 从头扫描到尾,每当遇到
+ 或- ,就意味着「前面那一小段乘除运算已经结束了」。 - 对每个“块”里的
\times 和\div ,就按照从左到右的顺序一步步算,保证了乘除是按正确的顺序执行的——只要不碰到+ 或- ,就一直在乘除之内。 - 最后,当我们真正遇到
+ 或- 时,把这一块的运算结果整体地加到(或者减到)最终的答案上。 - 当表达式扫描完毕后,如果还有一小段乘除没合并到总结果,也要补上去。
这样就能保证先把乘除算完,再统一做加减,而且每一段乘除的结果用一个临时变量维护。
除法保留整数部分可以直接用 C++ 语言中的整除特性:
AC代码
#include <iostream>
#include <string>
#define ll long long
using namespace std;
ll clac() {
ll mul = 1; // 储存当前“乘除块”的中间结果
ll res = 0; // 最终累加结果
char c; // 用来逐个读取字符
ll t = 0; // 正在读取的数字
bool flag = false;// 标记上一运算符是不是 '/'
// 循环读取每个非空字符
while (cin >> c) {
// 如果读到数字,就组装到 t
if (c >= '0' && c <= '9') {
t = t * 10 + (c - '0');
}
// 遇到加号 '+',把这段“乘除”结算进res,开启新的段
else if (c == '+') {
if (flag) { // 如果前一运算符是除号
mul /= t;
flag = false;
} else { // 如果前一运算符是乘号
mul *= t;
}
res += mul; // 这一块算完了,加到res
mul = 1; // 开启新块 (正号块)
t = 0; // 清空t以便下次读数字
}
// 遇到减号 '-',同理
else if (c == '-') {
if (flag) {
mul /= t;
flag = false;
} else {
mul *= t;
}
res += mul;
mul = -1; // 准备新的块,但带一个负号
t = 0;
}
// 遇到乘号 '*'
else if (c == '*') {
if (flag) {
// 前一次是除号,需要先把那次除法算完
mul /= t;
flag = false;
} else {
// 前一次是乘号
mul *= t;
}
t = 0;
}
// 遇到除号 '/'
else if (c == '/') {
if (flag) {
// 如果仍旧是除法延续,先把之前的除法做完
mul /= t;
} else {
// 否则先做乘法,再进入除法状态
mul *= t;
}
flag = true; // 标记:下次遇到数字时先完成除法
t = 0;
}
}
// 表达式读完,还有最后一段乘除要合并
if (flag) {
mul /= t;
flag = false;
} else {
mul *= t;
}
res += mul;
return res;
}
int main() {
cout << clac() << "\n";
return 0;
}
设字符串长度为