洛谷P1310 表达式的值 题解 栈/后缀表达式的应用
题目链接:https://www.luogu.org/problem/P1310
本题涉及算法:栈、前缀表达式转后缀表达式,动态规划思想。
这道题目我思考了好长时间,第一时间让我做的话我也做不出来。
看洛谷上面的题解给了我很大的启发。
其中最重要的两点启发是:
启发1:中缀加操作数预处理
将原始表达式中添加上‘.’,这些‘.’对应运算数(这么预处理能方便我接下来更方便地将前缀转后缀表达式进行处理);
启发2:动归思想
首先一个状态对应两个值,我暂且将它们设为 \(v0\) 和 \(v1\) ,其中:
- \(v0\) 表示该状态下结果为 \(0\) 的方案数;
- \(v1\) 表示该状态下结果为 \(1\) 的方案数。
那么,在前缀转中缀的时候,只有我们假设由两个状态 \(a\) 和 \(b\) 变换到新的状态 \(c\),那么:
- 如果进行的是
+
操作,则 \(c.v0 = a.v0 \times b.v0\) ,\(c.v1 = a.v0 \times b.v1 + a.v1 \times b.v0 + a.v1 \times b.v1\) ; - 如果进行的是
*
操作,则 \(c.v0 = a.v0 \times b.v0 + a.v0 \times b.v1 + a.v1 \times b.v0\) ,\(c.v1 = a.v1 \times b.v1\) 。
这里和原始的前缀转后缀的区别是:
- 原始进栈的都是一个个单独的操作数;
- 这里进行的都是一个个出事状态 \(p\) ,这些 \(p\) 满足 \(p.v0 = p.v1 = 1\)(即:单独一个数的时候结果为 \(0\) 或者为 \(1\) 的方案数都为 \(1\))。
实现代码如下:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200200;
const int MOD = 10007;
char s[maxn], t[maxn];
int m, n;
pair<int, int> num_stk[maxn];
char flag_stk[maxn];
int num_top, flag_top;
int main() {
scanf("%d%s", &m, s);
if (s[0] == '+' || s[0] == '*') t[n++] = '.';
for (int i = 0; s[i]; i ++) {
t[n++] = s[i];
if ( (s[i] == '+' || s[i] == '*' || s[i] == '(') && (!s[i+1] || s[i+1] != '(') )
t[n++] = '.';
}
for (int i = 0; i < n; i ++) {
if (t[i] == '.') {
num_stk[++ num_top] = make_pair(1, 1);
while (flag_top > 0 && flag_stk[flag_top] == '*') {
flag_top --;
pair<int, int> p1 = num_stk[num_top --];
pair<int, int> p2 = num_stk[num_top --];
num_stk[++ num_top] = make_pair(
( p1.first * p2.first + p1.first * p2.second + p1.second * p2.first ) % MOD,
p1.second * p2.second % MOD
);
}
}
else if (t[i] == '+') {
while (flag_top > 0 && flag_stk[flag_top] == '*') {
flag_top --;
pair<int, int> p1 = num_stk[num_top --];
pair<int, int> p2 = num_stk[num_top --];
num_stk[++ num_top] = make_pair(
( p1.first * p2.first + p1.first * p2.second + p1.second * p2.first ) % MOD,
p1.second * p2.second % MOD
);
}
while (flag_top > 0 && flag_stk[flag_top] == '+') {
flag_top --;
pair<int, int> p1 = num_stk[num_top --];
pair<int, int> p2 = num_stk[num_top --];
num_stk[++ num_top] = make_pair(
p1.first * p2.first % MOD,
( p1.first * p2.second + p1.second * p2.first + p1.second * p2.second ) % MOD
);
}
flag_stk[++ flag_top] = '+';
}
else if (t[i] == '(' || t[i] == '*') {
flag_stk[++ flag_top] = t[i];
}
else if (t[i] == ')') {
while (flag_top > 0 && flag_stk[flag_top] != '(') {
if (flag_stk[flag_top] == '*') {
flag_top --;
pair<int, int> p1 = num_stk[num_top --];
pair<int, int> p2 = num_stk[num_top --];
num_stk[++ num_top] = make_pair(
( p1.first * p2.first + p1.first * p2.second + p1.second * p2.first ) % MOD,
p1.second * p2.second % MOD
);
}
else if (flag_stk[flag_top] == '+') {
flag_top --;
pair<int, int> p1 = num_stk[num_top --];
pair<int, int> p2 = num_stk[num_top --];
num_stk[++ num_top] = make_pair(
p1.first * p2.first % MOD,
( p1.first * p2.second + p1.second * p2.first + p1.second * p2.second ) % MOD
);
}
}
flag_top --; // remove '('
}
}
while (flag_top > 0) {
if (flag_stk[flag_top] == '*') {
flag_top --;
pair<int, int> p1 = num_stk[num_top --];
pair<int, int> p2 = num_stk[num_top --];
num_stk[++ num_top] = make_pair(
( p1.first * p2.first + p1.first * p2.second + p1.second * p2.first ) % MOD,
p1.second * p2.second % MOD
);
}
else if (flag_stk[flag_top] == '+') {
flag_top --;
pair<int, int> p1 = num_stk[num_top --];
pair<int, int> p2 = num_stk[num_top --];
num_stk[++ num_top] = make_pair(
p1.first * p2.first % MOD,
( p1.first * p2.second + p1.second * p2.first + p1.second * p2.second ) % MOD
);
}
}
printf("%d\n", num_stk[1].first);
return 0;
}
这里虽然我过了代码,但是我觉得我对后缀表达式的理解还没有达到那种深度。所以后续还是需要进一步理解如果方便快捷地进行前缀到后缀表达式的转换。
作者:zifeiy
洛谷P1310 表达式的值 题解 栈/后缀表达式的应用的更多相关文章
- 洛谷P1981 表达式求值 题解 栈/中缀转后缀
题目链接:https://www.luogu.org/problem/P1981 这道题目就是一道简化的中缀转后缀,因为这里比较简单,只有加号(+)和乘号(*),所以我们只需要开一个存放数值的栈就可以 ...
- 洛谷 P5146 最大差值 题解
P5146 最大差值 题目描述 HKE最近热衷于研究序列,有一次他发现了一个有趣的问题: 对于一个序列\(A_1,A_2\cdots A_n\),找出两个数\(i,j\),\(1\leq i< ...
- 洛谷 P1351 联合权值 题解
P1351 联合权值 题目描述 无向连通图 \(G\) 有 \(n\) 个点,\(n-1\) 条边.点从 \(1\) 到 \(n\) 依次编号,编号为 \(i\) 的点的权值为 \(W_i\),每条 ...
- 2019.06.17课件:[洛谷P1310]表达式的值 题解
P1310 表达式的值 题目描述 给你一个带括号的布尔表达式,其中+表示或操作|,*表示与操作&,先算*再算+.但是待操作的数字(布尔值)不输入. 求能使最终整个式子的值为0的方案数. 题外话 ...
- 【洛谷P1310 表达式的值】
题目链接 题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算.例如:计算表达式 ...
- 洛谷P4047 [JSOI2010]部落划分题解
洛谷P4047 [JSOI2010]部落划分题解 题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落 ...
- [题解]P1449 后缀表达式(栈)
题目链接:P1449 后缀表达式 题目描述: 所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优 ...
- 洛谷P1783 海滩防御 分析+题解代码
洛谷P1783 海滩防御 分析+题解代码 题目描述: WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和 ...
- 中缀表达式转逆波兰式(后缀表达式)求值 C++ Stack
给一个包含小数的中缀表达式 求出它的值 首先转换为后缀表达式然后利用stack求出值 转换规则: 如果字符为'(' push else if 字符为 ')' 出栈运算符直到遇到‘(' else if ...
随机推荐
- OpenLayers添加地图标记
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...
- KiCad 工程用 Git 管理需要忽略哪些文件?
KiCAD 工程用 Git 管理需要忽略哪些文件? KiCAD 使用的 文本格式,天生可以用 Git 来管理. 但是并非所有文件需要使用 Git 管理,以下文件可以忽略. *.bak fp-info- ...
- 国内首个全域边缘节点服务发布,阿里云助力企业把握5G机遇
7月24日,阿里云峰会开发者大会在上海世博中心举办.作为2019年首场最受瞩目的云计算开发者大会,阿里云携一众云计算技术大牛与开发者面对面,探讨各自领域的技术干货与前沿趋势.同时,也发布了多项重大重磅 ...
- Python 中的 map, reduce, zip, filter, lambda基本使用方法
map(function, sequence[, sequence, ...] 该函数是对sequence中的每个成员调用一次function函数,如果参数有多个,则对每个sequence中对应的元素 ...
- python LEGB原理简要介绍
- LA4094 WonderTeam
杯哥题解. //Serene #include<algorithm> #include<iostream> #include<cstring> #inclu ...
- datepicker插件的使用
教程链接:http://www.runoob.com/jqueryui/example-datepicker.html 参数:http://hare6.blog.163.com/blog/static ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第一章:向量代数
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第一章:向量代数 学习目标: 学习如何使用几何学和数字描述 Vecto ...
- 2019-3-21-win10-uwp-修改图片质量压缩图片
title author date CreateTime categories win10 uwp 修改图片质量压缩图片 lindexi 2019-03-21 15:29:20 +0800 2019- ...
- Java练习 SDUT-3349_答答租车系统(面向对象综合练习)
答答租车系统(面向对象综合练习) Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 各位面向对象的小伙伴们,在学习了面向对 ...