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;
}
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16404613.html