洛谷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 ...
随机推荐
- Etag 和 If-None-Match
ETag是HTTP1.1中才加入的一个属性,用来帮助服务器控制Web端的缓存验证. 它的原理是这样的,当浏览器请求服务器的某项资源(A)时, 服务器根据A算出一个哈希值(3f ...
- CSS中各种居中方法
CSS中各种居中方法,本文回顾一下,便于后续的使用. 水平居中方法 1.行内元素居中 行内元素居中是只针对行内元素的,比如文本(text).图片(img).按钮等行内元素,可通过给父元素设置 text ...
- 26718汉字,gbk是23940个汉字,gb18030有76556个汉字
1 a 厑 吖 呵 啊 嗄 嬶 腌 錒 锕 阿 仰 卬 岇 昂 昻 枊 盎 肮 腌 軮 醠 雵 骯 侒 俺 儑 匎 匼 厂 厈 唵 啽 垵 埯 堓 媕 安 屵 岸 峎 峖 广 庵 按 揞 晻 暗 案 ...
- go struct 继承
- SpringMvc表单标签库
HTML密码框 <td><form:label path="password">密码:</form:label></td><t ...
- R语言Switch语句
R语言Switch语句 switch语句允许一个变量值的列表来平等进行测试.每个值被称为一个条件(情况),变量被接通检查每个条件(情况). 语法 在R语言中创建switch语句的基本语法是: 以下规则 ...
- 解决Dynamic Web Module 3.0 requires Java 1.6 or newer.问题
在项目的pom.xml的<build></build>标签中增加: <plugins> <plugin> <gro ...
- JavaScript--时间日期格式化封装
这是一个正常的封装: 其他非正常的请按照以下语句自由搭配 <!DOCTYPE html> <html lang="en"> <head> < ...
- 【To Read】LeetCode | Jump Game II(转载)
题目: Given an array of non-negative integers, you are initially positioned at the first index of the ...
- UVA_489:Hangman Judge
Language:C++ 4.8.2 #include<stdio.h> #include<string.h> int main(void) { ]; ]; ]; ]; // ...