NC16539 [NOIP2013]表达式求值

题目

题目描述

给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

输入描述

输入仅有一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘法运算符“*”,且没有括号。
所有参与运算的数字均为 02311 之间的整数。
输入数据保证这一行只有 0 ~ 9 、+ 、*这12种字符。

输出描述

输出只有一行,包含一个整数,表示这个表达式的值。注意:当答案长度多于 4 位时,请只输出最后 4 位,前导 0 不输出。

示例1

输入

1+1*3+4

输出

8

说明

计算的结果为 8 ,直接输出 8

示例2

输入

1+1234567890*1

输出

7891

说明

计算的结果为 1234567891 ,输出后 4 位,即 7891

示例3

输入

1+1000000003*1

输出

4

说明

计算的结果为 1000000004 ,输出后 4 位,即 4

备注

对于 30% 的数据, 0 ≤表达式中加法运算符和乘法运算符的总数≤ 100
对于 80% 的数据, 0 ≤表达式中加法运算符和乘法运算符的总数≤ 1000
对于 100% 的数据,0 ≤表达式中加法运算符和乘法运算符的总数≤ 100000

题解

方法一

知识点:分治。

表达式的运算有优先级直接读取难以计算,但运算总有最后一步,通过找到最后一次的运算将表达式以这个符号拆成左右两部分,就可以展开递归进行相同的操作。每次只需要遍历一遍当前表达式,找到所有符号最后出现的位置,加号优先判断,如果加号没有位置那就看乘号,来决定下一次拆分,如果都没有的话那说明是个纯数字,就字符串转换数字即可。注意到结果保留末四位,等价于模 10000,因为加法乘法在模意义下也具有意义。

此解法属于万能解法,可以十分方便处理所有运算符的一系列计算(包括但不限于加,减,乘,除,乘方,阶乘),而且可以通过改进变为可以带括号。平均复杂度 O(nlogn) ,但如果每次拆分都在最左最右,那么会退化到 O(n2) ,而本题有连续加的特殊数据因此在加法处判断后立即break可以优化。但如果是乘法则无法直接break优化,因为无法确定后方是否有更小优先级的运算符,但本题没有连续乘法的数据qwq。

时间复杂度 平均:O(nlogn) 最差: O(n2)

空间复杂度 O(n)

方法二

知识点:模拟。

发现连续乘法的数字可以连续算出放入临时变量,然后加入最终答案,因为只有加法和乘法。

时间复杂度 O(n)

空间复杂度 O(n)

代码

方法一

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e4;
string s;
int StoI(int l, int r) {
int ans = 0;
for (int i = l;i <= r;i++) ans = (10 * ans + s[i] - '0') % mod;
return ans;
}
int calc(int l, int r) {
int pos[2] = { -1,-1 };///+,*
for (int i = l;i <= r;i++) {///找到最后一次出现的符号(因为没有括号直接找最后一次的)
if (s[i] == '+') {
pos[0] = i;
break;
}///找到+可以直接退出,避免最差复杂度
else if (s[i] == '*') pos[1] = i;
}
if (!~pos[0] && !~pos[1]) return StoI(l, r);///纯数
else if (~pos[0]) return (calc(l, pos[0] - 1) + calc(pos[0] + 1, r)) % mod;
else if (~pos[1]) return calc(l, pos[1] - 1) * calc(pos[1] + 1, r) % mod;
return 0;///过编译
}
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> s;
cout << calc(0, s.length() - 1) << '\n';
return 0;
}

方法二

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e4;
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
string s;
cin >> s;
s += '+';///终止最后一段
int ans = 0;
for (int i = 0, tmp = 0, last = 1;i < s.length();i++) {///tmp指一个数字,last指一个乘法数块
if ('0' <= s[i] && s[i] <= '9') tmp = (tmp * 10 + s[i] - '0') % mod;///更新tmp
else if (s[i] == '+') {///把tmp乘进last,更新ans、tmp、last
last = last * tmp % mod;
ans = (ans + last) % mod;
tmp = 0;
last = 1;
}
else if (s[i] == '*') {///把tmp乘进last,更新tmp
last = last * tmp % mod;
tmp = 0;
}
}
cout << ans << '\n';
return 0;
}
posted @   空白菌  阅读(512)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示