题目链接: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. Linux下安装配置maven

    参考博客: http://www.blogjava.net/caojianhua/archive/2011/04/02/347559.html 注意事项: 1.解压目录 我的maven解压目录为: / ...

  2. 用Direct2D和DWM来做简单的动画效果

    原文:用Direct2D和DWM来做简单的动画效果 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sunnyloves/article/detail ...

  3. js实现动态计数效果

    下面附有数字图片和数字边框图 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  4. pytest fixture中scope试验,包含function、module、class、session、package

    上图是试验的目录结构 conftest.py:存放pytest fixture的文件 import uuid import pytest @pytest.fixture(scope="mod ...

  5. 移动端的touch事件(一)

    如果我们允许用户在页面上用类似桌面浏览器鼠标手势的方式来控制WEB APP,这个页面上肯定是有很多可点击区域的,如果用户触摸到了那些可点击区域怎么办呢?? 诸如智能手机和平板电脑一类的移动设备通常会有 ...

  6. PHP学习(语言结构语句)

    switch case语句 for循环语句: foreach循环语句 常用于遍历数组,一般有两种使用方式:不取下标.取下标. (1)只取值,不取下标 <?php foreach (数组 as 值 ...

  7. Significance A and B for protein ratios

    实验设计中,一般会做三个生物学重复来确保结果的准确性,尤其在下游分析中.但有时会遇到没有生物学重复,而又需要进行差异分析的情况,这时一般建议考虑foldchange即可,因为根本无法进行T-test等 ...

  8. 实现手机网页调起原生微信朋友圈分享的工具nativeShare.js

    http://www.liaoxiansheng.cn/?p=294 我们知道现在我们无法直接通过js直接跳转到微信和QQ等软件进行分享,但是现在像UC浏览器和QQ浏览器这样的主流浏览器自带一个分享工 ...

  9. 【python小随笔】List列表的常见函数与切片

    eval()的使用 n = ["2.3","2.56"] m = [] for i in n: k = eval(i) #只是去了最外层的双引号,单引号, 规定 ...

  10. day40-Spring 01-上次课内容回顾