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;
}

NC16539 [NOIP2013]表达式求值的更多相关文章

  1. NOIP2013 表达式求值

    题目描述 Description 给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值. 输入描述 Input Description 输入仅有一行,为需要你计算的表达式,表达式中只包含数字. ...

  2. NOIP2013普及组 T2 表达式求值

    OJ地址:洛谷P1981 CODEVS 3292 正常写法是用栈 #include<iostream> #include<algorithm> #include<cmat ...

  3. [NOIP2013 普及组] 表达式求值

    [NOIP2013 普及组] 表达式求值 给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值. Input 一行,为需要你计算的表达式,表达式中只包含数字.加法运算符"+" ...

  4. 表达式求值(noip2015等价表达式)

    题目大意 给一个含字母a的表达式,求n个选项中表达式跟一开始那个等价的有哪些 做法 模拟一个多项式显然难以实现那么我们高兴的找一些素数代入表达式,再随便找一个素数做模表达式求值优先级表 - ( ) + ...

  5. 用Python3实现表达式求值

    一.题目描述 请用 python3 编写一个计算器的控制台程序,支持加减乘除.乘方.括号.小数点,运算符优先级为括号>乘方>乘除>加减,同级别运算按照从左向右的顺序计算. 二.输入描 ...

  6. 数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值

    一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚, ...

  7. nyoj305_表达式求值

    表达式求值 时间限制:3000 ms  |  内存限制:65535 KB 难度:3   描述 Dr.Kong设计的机器人卡多掌握了加减法运算以后,最近又学会了一些简单的函数求值,比如,它知道函数min ...

  8. 利用栈实现算术表达式求值(Java语言描述)

    利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...

  9. 数据结构--栈的应用(表达式求值 nyoj 35)

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=35 题目: 表达式求值 时间限制:3000 ms | 内存限制:65535 KB描述 AC ...

随机推荐

  1. 初始celery

    使用celery执行异步任务 下载celery,redis pip3 install celery#在这里我使用的是celery==4.2.2#当celery版本过低的话celery配置可能会略有不同 ...

  2. Linux的Docker安装教程

    Docker下载的官方文档地址:https://docs.docker.com/engine/install/centos/ 卸载旧版本 sudo yum remove docker \ docker ...

  3. 给swap分区扩容

    一.先添加一块硬盘,如果硬盘空间还有没有被分区的也可以使用,再创建一个分区(分区可以是主分区或者扩展的逻辑分区) fdisk  /dev/sdb n        代表创建分区 p        代表 ...

  4. C# 核心

    C# 核心 面向对象编程概念 面向过程编程是一种以过程为中心的编程思想,分析出解决问题所需要的步骤,然后有函数把步骤一步一步实现,使用的时候一个一个依次调用. 面向对象是一种对现实世界理解和抽象的编程 ...

  5. 华硕主板安装Ubuntu双系统无法启动解决办法

    问题描述: 在安装完Ubuntu后,开机后没有启动项可以选择,而是直接进入win10系统. 解决办法: 开机进入bios,选择 高级模式 (Advance model),进入 启动(boot)选项卡, ...

  6. JDBC往数据库传值中文乱码以及时区不一致解决

    设置一下时区和编码就可以了 "jdbc:mysql://localhost:3306/jdbcprac?characterEncoding=UTF-8&&useSSL=fal ...

  7. iptables系列教程(一)| iptables入门篇

    一个执着于技术的公众号 前言 在早期的 Linux 系统中,默认使用的是 iptables 配置防火墙.尽管新型 的 firewalld 防火墙已经被投入使用多年,但是大量的企业在生产环境中依然出于各 ...

  8. CentOS 8及以上版本配置IP的方法,你 get 了吗

    接上篇文章讲了 Ubuntu 18及以上版本的配置方法,本文再来讲讲 CentOS 8 及以上版本配置 IP 的方法. Centos/Redhat(8.x) 配置 IP 方法 说明:CentOS 8 ...

  9. DOM0级同DOM2级

    DOM0级分为两个:一是写在标签内的onclick事件: <button id="btn" onclick="alert('happy')">按钮& ...

  10. C# 随机给一个全部信息都未知的类类型,如何获取该类的类名、属性个数、属性名、属性的数据类型、属性值?

    一.场景假设 假设现在有一个泛型类T的实例对象t,该T类的全部信息都未知. 要求:打印输出实例对象t的类名.属性个数.属性名.属性的数据类型.属性值. 二.解决问题 1.我们根据输出的内容要求定义一个 ...