洛谷表达式求值

本文介绍了一种计算仅包含加法和乘法的算术表达式的算法,通过逐个解析运算符和数字,利用循环和条件判断实现表达式的求值。特别关注了表达式的长度和运算符数量限制,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


题目描述

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

一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+++”和乘法运算符“× \times ×”,且没有括号,所有参与运算的数字均为 000 到 231−12^{31}-1231−1 之间的整数。

输入数据保证这一行只有0−9 0-90−9、+++、× \times ×这 1212 12种字符。

输出格式:

一个整数,表示这个表达式的值。

注意:当答案长度多于 444 位时,请只输出最后4 44 位,前导0 00 不输出。

输入输出样例
输入样例#1: 复制

1+1*3+4

输出样例#1: 复制

8

输入样例#2: 复制

1+1234567890*1

输出样例#2: 复制

7891

输入样例#3: 复制

1+1000000003*1

输出样例#3: 复制

4

说明

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

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

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

思路
如果 此时得到的是加号那么说明前面的运算可以结束了,继续下面的处理
如果得到的是乘号那么需要接着上一部分处理

别忘了 clt +z

#include<iostream>
#include<cstdio>
using namespace std;
int main(){
	int ans=0,p,a;
	char s;
	cin>>p;
	while(cin>>s){
		cin>>a;
		if(s=='+'){
			ans+=p;
			ans%=10000;
			p=a;
		}else if(s=='*'){
			p*=a;
			p%=10000;
		}
	}
	ans+=p;
	printf("%d",ans%10000);
}

我还是好弱啊~~~~~

GP11306 安欣买酸奶 普及- 字符串 NOIp 普及组 模拟 2013 栈 表达式求值 标准IO 传统题 时间限制 1000ms 内存限制 256MB 通过/尝试次数 41/55 来源 洛谷 题目背景 猫叉老师刚才吃完 n n碗曹氏热卤之后,发现自己还是有些小瞧了曹氏的辣度,她的胃开始隐隐作痛,于是委托安欣老师去超市帮她买酸奶,而且要买很多很多的酸奶!!(众所周知酸奶是解辣神器) 由于超市店员忘了给安欣老师小票,于是安欣老师为了更好的找猫叉老师报销酸奶钱,就把买酸奶花的钱写成了一个算数表达式。(安欣其实也想请猫叉老师喝,但是毕竟破产了,还是把酸奶钱要一下吧) 题目描述 给定一个只包含加法乘法的算术表达式,请你编程计算表达式的值。 输入格式 一行,为需要你计算的表达式表达式中只包含数字加法运算符 + 乘法运算符 *,且没有括号,所有参与运算的数字均为 0 0 到 2 31 − 1 2 31 −1 之间的整数。 输入数据保证这一行只有 0123456789+* 这 12 12 种字符。 输出格式 一个整数,表示这个表达式的值。 注意:当答案长度多于 4 4 位时,请只输出最后 4 4 位,前导 0 0 不输出。 input1 复制代码 1+1*3+4 output1 复制代码 8 input2 复制代码 1+1234567890*1 output2 复制代码 7891 input3 复制代码 1+1000000003*1 output3 复制代码 4 提示 对于 30 % 30% 的数据, 0 ≤ 0≤ 表达式加法运算符乘法运算符的总数 ≤ 100 ≤100。 对于 80 % 80% 的数据, 0 ≤ 0≤ 表达式加法运算符乘法运算符的总数 ≤ 1000 ≤1000。 对于 100 % 100% 的数据, 0 ≤ 0≤ 表达式加法运算符乘法运算符的总数 ≤ 100000 ≤100000 双端队列 c++daima
最新发布
05-09
<think>嗯,用户需要的是用C++双端队列实现表达式求值,支持加法乘法,适用于NOIP普及组的栈相关题目。首先,我得想清楚表达式求值的常见方法,比如逆波兰表达式或者双栈法。不过用户提到双端队列,可能希望用队列结构来处理,或者结合栈队列的特性。 用户的问题可能涉及到中缀表达式的处理,需要处理运算符的优先级,尤其是乘法的优先级高于加法。这时候,双栈法可能更适合,一个栈存操作数,另一个存运算符。不过用户明确要求用双端队列,可能需要用双端队列来模拟栈的操作,或者用队列来管理操作数运算符的顺序。 另外,考虑到NOIP的题目通常会有输入输出的特定格式,比如表达式可能由数字、加号乘号组成,没有括号。这时候,处理起来需要按照运算符优先级来处理,先处理乘法,再处理加法。 比如,可能先遍历表达式,将数字运算符分离出来,存储到双端队列中。然后,先处理所有的乘法运算,将乘法的结果计算出来,并将结果放回队列,剩下的加法再依次处理。或者,在解析表达式的时候,遇到乘法就立即计算,而加法则延迟处理,这样可以利用双端队列来调整运算顺序。 可能需要分两个阶段处理:第一阶段处理所有乘法,第二阶段处理加法。例如,使用双端队列来存储中间结果,当遇到乘法时,取出前一个数相乘后再放回队列,而加法则直接保留到后续处理。这样,队列中剩下的都是需要相加的数,最后累加即可。 接下来,代码实现方面,需要考虑如何分割表达式中的数字运算符。可能需要逐个字符读取,遇到连续的数字字符时合并成整数。同时,处理运算符时,判断是乘法还是加法,执行相应的操作。 另外,双端队列的选择,C++中的deque结构比较适合,因为它支持前端后端的插入删除操作。例如,处理乘法时,可能需要从队列尾部取出操作数,计算后再放回,这样队列的前端可以继续处理后续的元素。 需要注意的是,表达式中的操作数可能是多位数,所以在解析时要正确处理,比如当前字符是数字时,继续读取直到遇到非数字字符,然后将整个数字字符串转换为整数。 可能的步骤: 1. 使用双端队列来存储解析后的数字运算符。 2. 首先处理所有的乘法运算,因为乘法的优先级更高。 3. 处理完乘法后,剩下的加法运算按顺序执行。 4. 最后队列中剩下的数字就是表达式的结果。 或者,另一种方法是使用两个双端队列,一个存数字,一个存运算符,按照运算符优先级处理。但可能复杂度更高。 参考引用中的线性筛动态规划可能不相关,但用户提供的引用里有关于C++的数据结构如vector、unordered_map等,但这里需要的是deque的应用。可能需要结合栈的思想,用双端队列来替代栈,因为deque可以在两端操作,方便处理某些情况。 比如,在双栈法中,运算符操作数栈,这里可以改用双端队列来存储运算符操作数。但可能需要调整处理顺序,因为双端队列允许两端操作,可能可以更灵活地处理运算符的优先级。 或者,可能用户希望用双端队列来实现类似调度的过程,将高优先级的运算符先处理。比如,遍历表达式,将数字运算符存入队列,当遇到乘法时,立即取出前一个数字当前数字相乘,结果存回队列,而加法则留在队列中,后续处理。 比如,假设表达式是3+5*2,解析后队列中有3, +, 5, *, 2。处理时,先处理乘法:当遇到*时,取出52相乘得到10,替换掉原来的5, *, 2部分,队列变为3, +, 10。然后处理加法,3+10=13。 这种方法需要遍历队列,遇到乘法运算符时进行处理,并将结果合并回队列。可能需要多次遍历队列,直到没有乘法运算符为止,然后再处理加法。但这样多次遍历可能效率不高,但在表达式不长的情况下是可行的。 另一种方法是,在解析表达式的时候,就立即处理乘法,这样只需要一次遍历。例如,维护一个当前结果,当遇到乘法时,取出前一个数相乘,否则保留加法到后续处理。 这可能更高效,需要维护一个中间值。例如,初始时,中间值是第一个数字,然后遍历后续的运算符数字。如果是乘法,就将中间值乘以当前数字,如果是加法,则将中间值存入队列,并将当前数字作为新的中间值。最后,队列中的所有数(包括最后的中间值)相加得到结果。 这种方法可能更高效,只需要一次遍历,并且利用队列来暂存需要加的数。例如,处理表达式3+5*2时,中间值初始为3,遇到+,将3存入队列,然后处理5,遇到*,中间值变为5*2=10,遍历结束后,队列中的310相加得到13。 这种方法可能更高效,只需要一次遍历,并且正确处理乘法的优先级。此时,双端队列用于存储需要相加的数,而中间处理乘法的结果。这样,乘法的处理在遇到时就立即计算,而加法则延迟到队列中的数累加。 这样的话,代码的大致结构可能是: 1. 分割表达式数字运算符的列表。 2. 初始化一个队列,用来存储需要相加的数。 3. 初始化当前值为第一个数字。 4. 遍历运算符数字: a. 如果当前运算符乘法,当前值 *= 下一个数字。 b. 如果是加法,将当前值加入队列,当前值设为下一个数字。 5. 遍历结束后,将当前值加入队列。 6. 累加队列中的所有数,得到最终结果。 这样,队列的作用是存储所有需要相加的项,而乘法在遍历过程中立即处理。这种方法避免了处理括号的情况,但符合题目中的加法乘法的需求。 因此,代码实现可以分为几个步骤: - 解析表达式,分割成数字运算符的列表。 - 使用上述逻辑处理乘法加法。 - 最后累加队列中的数。 在C++中,可以使用istringstream来分割表达式,或者手动遍历字符串处理数字运算符。例如,遍历每个字符,当遇到数字时,提取整个数字,遇到运算符时记录。 例如,对于表达式"3+5*2",解析为数字列表[3,5,2],运算符列表['+','*']。 然后,初始化current = 3,队列为空。遍历运算符: 第一个运算符是'+',所以将current(3)加入队列,然后current设为下一个数字5。接着,第二个运算符是'*',所以current *= 2 → 5*2=10。遍历结束后,将current(10)加入队列。队列中的数是310,总13。 这样处理是正确的。因此,代码的关键在于正确解析表达式,并正确处理乘法加法的顺序。 在解析表达式时,需要注意多位数的处理,例如"123+45*6",需要正确提取123,45,6这三个数字。 所以,代码的大体结构是: - 读取表达式字符串。 - 解析成数字运算符的向量。 - 处理乘法当前值,队列存储加法的操作数。 - 最后求。 关于双端队列的使用,这里可能用deque来存储需要相加的数,但其实用vector也可以,因为只需要在最后累加。但用户明确要求双端队列,所以需要使用deque结构。 综上,代码实现步骤如下: 1. 解析表达式到numsops。 2. 初始化deque,current_num = nums[0]。 3. 遍历i从0到ops.size()-1: a. op = ops[i] b. next_num = nums[i+1] c. 如果op是乘号,current_num *= next_num d. 否则,将current_num加入deque,current_num = next_num 4. 将current_num加入deque。 5. 累加deque中的所有元素。 这样,双端队列在这里的作用是存储所有需要相加的项,而乘法在遍历过程中立即计算。 现在,编写代码时需要注意: - 如何解析表达式字符串为numsops。例如,处理连续的数字字符转换为整数。 - 处理可能的空格,但题目可能假设表达式没有空格,如NOIP题目中的输入通常格式明确。 - 使用C++的deque,将结果压入队列,最后遍历队列求。 例如,解析部分的代码: string s = "3+5*2"; vector<int> nums; vector<char> ops; int num = 0; for (char c : s) { if (isdigit(c)) { num = num * 10 + (c - '0'); } else { nums.push_back(num); ops.push_back(c); num = 0; } } nums.push_back(num); // 处理最后一个数字 这样,对于表达式中的每个字符,如果是数字,就累积到num中,否则将num存入nums,运算符存入ops,并重置num。这样,nums的大小应该比ops大1。 然后处理乘法加法: deque<int> q; int current = nums[0]; for (int i = 0; i < ops.size(); ++i) { char op = ops[i]; int next = nums[i+1]; if (op == '*') { current *= next; } else { // '+' q.push_back(current); current = next; } } q.push_back(current); int sum = 0; while (!q.empty()) { sum += q.front(); q.pop_front(); } cout << sum << endl; 这样就能得到正确结果。这种方法符合用户的需求,使用双端队列来暂存加法的操作数,而乘法立即计算,从而处理了优先级问题。 需要注意的是,这种方法只能处理正确的表达式,没有错误处理,但符合竞赛题目的输入假设。 综上,这样的代码应该满足用户的要求。然后,根据用户提供的引用,可能参考引用中的动态规划部分,但这里并不需要,所以可能不需要引用。但用户的问题可能希望结合栈或队列,这里的双端队列用来替代栈的部分功能。</think>以下是用C++双端队列实现表达式求值的代码实现,支持加法乘法运算符优先级处理,适用于NOIP普及组题目: ```cpp #include <iostream> #include <deque> #include <string> using namespace std; int evaluate_expression(const string& s) { deque<int> nums; int current_num = 0; char prev_op = '+'; // 初始化为加法运算符 for (int i = 0; i < s.length(); ++i) { if (isdigit(s[i])) { current_num = current_num * 10 + (s[i] - '0'); } if (!isdigit(s[i]) || i == s.length() - 1) { if (prev_op == '+') { nums.push_back(current_num); } else if (prev_op == '*') { int prev = nums.back(); nums.pop_back(); nums.push_back(prev * current_num); } prev_op = s[i]; current_num = 0; } } int result = 0; while (!nums.empty()) { result += nums.front(); nums.pop_front(); } return result; } int main() { string expr = "3+5*2+4*6"; cout << evaluate_expression(expr) << endl; // 输出:3+10+24=37 return 0; } ``` ### 实现原理分步说明: 1. **数字解析**:遍历表达式字符串,连续数字字符转换为整数 2. **运算符处理**:使用`prev_op`记录前一个运算符 - 遇到`+`时暂存当前数字到双端队列 - 遇到`*`时立即计算队列尾部数字与当前数字的乘积 3. **结果计算**:最终将所有队列中的数字相加得到结果 ### 时间复杂度分析 - 时间复杂度:$O(n)$,仅需一次遍历即可完成计算 - 空间复杂度:$O(n)$,双端队列最多存储n/2个数字
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值