题目链接: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\))。

实现代码如下:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 200200;
  4. const int MOD = 10007;
  5. char s[maxn], t[maxn];
  6. int m, n;
  7. pair<int, int> num_stk[maxn];
  8. char flag_stk[maxn];
  9. int num_top, flag_top;
  10. int main() {
  11. scanf("%d%s", &m, s);
  12. if (s[0] == '+' || s[0] == '*') t[n++] = '.';
  13. for (int i = 0; s[i]; i ++) {
  14. t[n++] = s[i];
  15. if ( (s[i] == '+' || s[i] == '*' || s[i] == '(') && (!s[i+1] || s[i+1] != '(') )
  16. t[n++] = '.';
  17. }
  18. for (int i = 0; i < n; i ++) {
  19. if (t[i] == '.') {
  20. num_stk[++ num_top] = make_pair(1, 1);
  21. while (flag_top > 0 && flag_stk[flag_top] == '*') {
  22. flag_top --;
  23. pair<int, int> p1 = num_stk[num_top --];
  24. pair<int, int> p2 = num_stk[num_top --];
  25. num_stk[++ num_top] = make_pair(
  26. ( p1.first * p2.first + p1.first * p2.second + p1.second * p2.first ) % MOD,
  27. p1.second * p2.second % MOD
  28. );
  29. }
  30. }
  31. else if (t[i] == '+') {
  32. while (flag_top > 0 && flag_stk[flag_top] == '*') {
  33. flag_top --;
  34. pair<int, int> p1 = num_stk[num_top --];
  35. pair<int, int> p2 = num_stk[num_top --];
  36. num_stk[++ num_top] = make_pair(
  37. ( p1.first * p2.first + p1.first * p2.second + p1.second * p2.first ) % MOD,
  38. p1.second * p2.second % MOD
  39. );
  40. }
  41. while (flag_top > 0 && flag_stk[flag_top] == '+') {
  42. flag_top --;
  43. pair<int, int> p1 = num_stk[num_top --];
  44. pair<int, int> p2 = num_stk[num_top --];
  45. num_stk[++ num_top] = make_pair(
  46. p1.first * p2.first % MOD,
  47. ( p1.first * p2.second + p1.second * p2.first + p1.second * p2.second ) % MOD
  48. );
  49. }
  50. flag_stk[++ flag_top] = '+';
  51. }
  52. else if (t[i] == '(' || t[i] == '*') {
  53. flag_stk[++ flag_top] = t[i];
  54. }
  55. else if (t[i] == ')') {
  56. while (flag_top > 0 && flag_stk[flag_top] != '(') {
  57. if (flag_stk[flag_top] == '*') {
  58. flag_top --;
  59. pair<int, int> p1 = num_stk[num_top --];
  60. pair<int, int> p2 = num_stk[num_top --];
  61. num_stk[++ num_top] = make_pair(
  62. ( p1.first * p2.first + p1.first * p2.second + p1.second * p2.first ) % MOD,
  63. p1.second * p2.second % MOD
  64. );
  65. }
  66. else if (flag_stk[flag_top] == '+') {
  67. flag_top --;
  68. pair<int, int> p1 = num_stk[num_top --];
  69. pair<int, int> p2 = num_stk[num_top --];
  70. num_stk[++ num_top] = make_pair(
  71. p1.first * p2.first % MOD,
  72. ( p1.first * p2.second + p1.second * p2.first + p1.second * p2.second ) % MOD
  73. );
  74. }
  75. }
  76. flag_top --; // remove '('
  77. }
  78. }
  79. while (flag_top > 0) {
  80. if (flag_stk[flag_top] == '*') {
  81. flag_top --;
  82. pair<int, int> p1 = num_stk[num_top --];
  83. pair<int, int> p2 = num_stk[num_top --];
  84. num_stk[++ num_top] = make_pair(
  85. ( p1.first * p2.first + p1.first * p2.second + p1.second * p2.first ) % MOD,
  86. p1.second * p2.second % MOD
  87. );
  88. }
  89. else if (flag_stk[flag_top] == '+') {
  90. flag_top --;
  91. pair<int, int> p1 = num_stk[num_top --];
  92. pair<int, int> p2 = num_stk[num_top --];
  93. num_stk[++ num_top] = make_pair(
  94. p1.first * p2.first % MOD,
  95. ( p1.first * p2.second + p1.second * p2.first + p1.second * p2.second ) % MOD
  96. );
  97. }
  98. }
  99. printf("%d\n", num_stk[1].first);
  100. return 0;
  101. }

这里虽然我过了代码,但是我觉得我对后缀表达式的理解还没有达到那种深度。所以后续还是需要进一步理解如果方便快捷地进行前缀到后缀表达式的转换。

作者:zifeiy

洛谷P1310 表达式的值 题解 栈/后缀表达式的应用的更多相关文章

  1. 洛谷P1981 表达式求值 题解 栈/中缀转后缀

    题目链接:https://www.luogu.org/problem/P1981 这道题目就是一道简化的中缀转后缀,因为这里比较简单,只有加号(+)和乘号(*),所以我们只需要开一个存放数值的栈就可以 ...

  2. 洛谷 P5146 最大差值 题解

    P5146 最大差值 题目描述 HKE最近热衷于研究序列,有一次他发现了一个有趣的问题: 对于一个序列\(A_1,A_2\cdots A_n\)​,找出两个数\(i,j\),\(1\leq i< ...

  3. 洛谷 P1351 联合权值 题解

    P1351 联合权值 题目描述 无向连通图 \(G\) 有 \(n\) 个点,\(n-1\) 条边.点从 \(1\) 到 \(n\) 依次编号,编号为 \(i\) 的点的权值为 \(W_i\)​,每条 ...

  4. 2019.06.17课件:[洛谷P1310]表达式的值 题解

    P1310 表达式的值 题目描述 给你一个带括号的布尔表达式,其中+表示或操作|,*表示与操作&,先算*再算+.但是待操作的数字(布尔值)不输入. 求能使最终整个式子的值为0的方案数. 题外话 ...

  5. 【洛谷P1310 表达式的值】

    题目链接 题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算.例如:计算表达式 ...

  6. 洛谷P4047 [JSOI2010]部落划分题解

    洛谷P4047 [JSOI2010]部落划分题解 题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落 ...

  7. [题解]P1449 后缀表达式(栈)

    题目链接:P1449 后缀表达式 题目描述: 所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优 ...

  8. 洛谷P1783 海滩防御 分析+题解代码

    洛谷P1783 海滩防御 分析+题解代码 题目描述: WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和 ...

  9. 中缀表达式转逆波兰式(后缀表达式)求值 C++ Stack

    给一个包含小数的中缀表达式 求出它的值 首先转换为后缀表达式然后利用stack求出值 转换规则: 如果字符为'('  push else if 字符为 ')' 出栈运算符直到遇到‘(' else if ...

随机推荐

  1. androidstudio如何用github多人开发

    一.首先我们利用github作为代码库,有两种方法可以创建代码库 一定要配置好git环境和创建好github账号 检测git环境配置 检测github账号是否能登录 成功就会 (1)在github中直 ...

  2. web前端学习(二)html学习笔记部分(1) -- html5新增的元素及特性等等

    检查,在浏览器中可以调整设备类型 html5实现水池效果. lang:en为英文语言,中文语言zh <html lang="en"> <head> < ...

  3. 光(mirror room)

    /* 光线只有遇上边界或堵塞的格子才会改变方向,所以改变方向的位置是有限的,光线的方向又最多只有四种,所以光线在循环之前改变方向的次数是O(n+m+k)级别的.我们可以模拟光线的移动.已知光线位置和光 ...

  4. 【JZOJ3635】【BOI2012】Peaks

    ╰( ̄▽ ̄)╭ 有一个居住在多山岛屿的登山家,已经攀上了一座山峰,并且要攀爬另外一座更高的山峰. 更精确地说,岛上的每一点都有一个大于零的海拔(海面的海拔为零),并且如果登山家位于海拔Ei的山峰上,那 ...

  5. Leetcode674.Longest Continuous Increasing Subsequence最长连续递增序列

    给定一个未经排序的整数数组,找到最长且连续的的递增序列. 示例 1: 输入: [1,3,5,4,7] 输出: 3 解释: 最长连续递增序列是 [1,3,5], 长度为3. 尽管 [1,3,5,7] 也 ...

  6. Leetcode766.Toeplitz Matrix托普利茨矩阵

    如果一个矩阵的每一方向由左上到右下的对角线上具有相同元素,那么这个矩阵是托普利茨矩阵. 给定一个 M x N 的矩阵,当且仅当它是托普利茨矩阵时返回 True. 示例 1: 输入: matrix = ...

  7. PHP学习(类和对象)——基本概念

    类是面向对象程序设计的基本概念,通俗的理解类就是对现实中某一个种类的东西的抽象, 比如汽车可以抽象为一个类,汽车拥有名字.轮胎.速度.重量等属性,可以有换挡.前进.后退等操作方法. 每个类的定义都以关 ...

  8. 深入浅出Cocoa 之动态创建类【转】

    在前文<深入浅出Cocoa之类与对象>一文中,我已经详细介绍了ObjC中的 Class 与 Object 的概念,今天我们来如何在运行 时动态创建类.下面这个函数就是应用前面讲到的Clas ...

  9. 【JZOJ4803】【NOIP2016提高A组模拟9.28】求导

    题目描述 输入 输出 样例输入 2x^2+3x+1 样例输出 4x+3 数据范围 样例解释 求导的意思: 多项式是由若干个单项式构成的 单项式的一般形式是ax^b,其中ab都是常数,x是自变量 对于单 ...

  10. 阿里云区块链共创会:BaaS正式商业化 广邀合作伙伴共建生态

    摘要: 阿里云宣布区块链服务Hyperledger Fabric版正式商业化,并发布生态合作伙伴计划. 2019年3月29日,阿里云区块链于深圳召开正式商业化共创会,宣布区块链服务Hyperledge ...