NC16539 [NOIP2013]表达式求值

题目

题目描述

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

输入描述

输入仅有一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘法运算符“*”,且没有括号。

所有参与运算的数字均为 \(0\) 到 \(2^{31}-1\) 之间的整数。

输入数据保证这一行只有 \(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(n\log n)\) ,但如果每次拆分都在最左最右,那么会退化到 \(O(n^2)\) ,而本题有连续加的特殊数据因此在加法处判断后立即break可以优化。但如果是乘法则无法直接break优化,因为无法确定后方是否有更小优先级的运算符,但本题没有连续乘法的数据qwq。

时间复杂度 平均:\(O(nlogn)\) 最差: \(O(n^2)\)

空间复杂度 \(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;
}

最新文章

  1. Android之使用Bundle进行IPC
  2. django学习记录
  3. Java web--Filter过滤器分IP统计访问次数
  4. .NET entityframework for mysql ,datetime字段存储值时有误差
  5. connect VisualVM to Tomcat
  6. Linux中安装和使用rz、sz命令
  7. Atitti.java exp ast java表达式语法ast构造器
  8. chrome https添加信任
  9. sql基础查询语句
  10. javascript设计模式--备忘录模式(Memento)
  11. Linq无聊练习系列7----Insert,delete,update,attach操作练习
  12. jquery点击选中,再次点击取消选中
  13. java.io.OutputStream &amp; java.io.FileOutputStream
  14. LexAndYacc 安装程序
  15. c++/ boost 库常见错误及解决方法总结
  16. php实现异步请求
  17. 将Java项目从maven迁移到gradle
  18. 用Swift实现一款天气预报APP(一)
  19. 【[HAOI2015]树上染色】
  20. SDN openflow 学习小得

热门文章

  1. Sentinel基础应用
  2. 进阶实战 css 点击按钮的样式
  3. Docker部署PostgreSQL主从
  4. 人机验证reCAPTCHA v3使用完备说明
  5. CoreWCF 1.0.0 发布,微软正式支持WCF
  6. [ubuntu18.04 python3.6] 清华源 CondaHTTPError: HTTP 000 CONNECTION
  7. Java SPI 和 API,傻傻分不清?
  8. redis数据结构附录
  9. gogin web框架部署学习
  10. 谈谈最近玩的设计软件:Figma 与 Sketch