题目链接: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 表达式的值 题解 栈/后缀表达式的应用的更多相关文章

  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. HTML input type=file文件选择表单的汇总(二)

    1. 原生file input大小.按钮文字等UI自定义 元素input的原生样式,不是太好看: 有一种方法是这样的:让file类型的元素透明度0,覆盖在我们好看的按钮上.然后我们去点击好看的按钮,实 ...

  2. _STORAGE_WRITE_ERROR_:./Application/Runtime/Cache/Home/f8995a0e1afcdadc637612fae5a3b585.php

    将one think部署到服务器上出现下面的问题 _STORAGE_WRITE_ERROR_:./Application/Runtime/Cache/Home/f8995a0e1afcdadc6376 ...

  3. CB Insights,201608月174家独角兽榜单出炉,上榜的33家中国公司都是谁?

    全球最新独角兽榜单出炉,上榜的33家中国公司都是谁? Monica  2016-09-15   近日,美国市场调研公司CB Insights发布了全球独角兽榜单(估值10亿美元以上),共有来自21个国 ...

  4. pillow模块

    pillow模块 用于操作图片的模块 安装 pip install pillow 生成验证码 from PIL import Image,ImageDraw,ImageFont from io imp ...

  5. Codeforces Round #197 (Div. 2) A. Helpful Maths【字符串/给一个连加计算式,只包含数字 1、2、3,要求重新排序,使得连加的数字从小到大】

    A. Helpful Maths time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  6. Java连接Neo4j的两种方式

    1.Neo4j数据库的两种方式 Neo4j可以以两种方式运行: Java应用程序中的嵌入式数据库 通过REST的独立服务器 不管哪一种方式,这个选择不会影响查询和使用数据库的方式. 它是由应用程序的性 ...

  7. 开源中国 ThinkPHP 领奖

    开源中国 ThinkPHP 的领奖 周日早上早早就起来参考开源中国的活动. 由于今年竞争激烈 FastAdmin 没有上榜,但是没关系,因为这说明整个开源环境越来越好了,对于我们来说是利好. 因为 T ...

  8. vsync信号产生与分发

    以下分析基于android 4.4代码 vsync信号的产生.分发涉及到以下几个类,先主要了解下他们各自的功能: HWComposer:产生hardware vsync,post fb VSyncTh ...

  9. SQLServer —— 数据类型的转换

    一.使用convert函数实现强制转换 例如我们现在有如下一张学员成绩表: 现在想查询学号等于100003的学员总成绩,并按照要求打印出来,我们可以这样实现: 结果报错,因为最后一句字符串不能和数值相 ...

  10. SpringBoot Cloud eureka 注册中心

    SpringBoot Cloud是什么 Spring Cloud是一个分布式的整体解决方案. Spring Cloud 为开发者提供了在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一 ...