题目传送

题的难点:1、有运算优先级,不好判断。2、有破坏整体和谐性的讨厌的括号。3、不知道哪里要填数。4、要求方案数很大,搜索不会做呐。

发现难点1和2都是中缀表达式的缺点。转成后缀表达式后难点1、2就烟消云散了。

普及一下:

  前缀表达式(又称波兰表达式)与后缀表达式(又称逆波兰表达式)较我们平常使用的中缀表达式,最主要的特点是没有括号。前/后缀表达式是一种十分有用的表达式,将中缀表达式转换为前缀表达式后,就可以只依靠出栈、入栈两种简单操作完全解决中缀表达式的全部运算。而平常我们一般都用后缀表达式(顺序从前到后,而前缀表达式的扫描顺序是从后向前)。

  计算后缀表达式,只要我们从前到后扫描,遇到数就入栈,遇到运算符就出栈两个数进行相应运算,最终弄结果再入栈。

  这里给出一个中缀表达式转后缀表达式的方法(建树什么的就别提了):

  设用一个结果栈和一个符号栈。从前向后扫描中缀表达式:

  1、若遇到数,直接入结果栈;

  2、若遇到运算符,弹出符号栈栈顶连续的优先级高于它的运算符,让那些运算符按弹出顺序依次入结果栈后再自己入符号栈;

  3、若遇到左括号,直接入符号栈;

  4、若遇到右括号,一直弹出符号栈至第一次弹出左括号,将弹出的运算符(不包括括号)按弹出顺序依次入结果栈;

  5、若扫描完中缀表达式后符号栈栈非空,则将符号栈元素全部弹出,将弹出的运算符按弹出顺序依次入结果栈。

  最后结果栈存的就是转换完的后缀表达式。计算时只要从结果栈的栈底开始扫,按照后缀表达式的计算过程计算即可。

再考虑从哪里填数。发现当我们无视括号时,剩下运算符的前后都会有一个数、相邻两运算符间也会有一个数。加上括号后只会改变运算顺序,不会改变数的数量。考虑起始时在结果栈先入一个数,每次遇到加号或乘号后再入一个数。辩证正确性:如果该加号(或乘号)后面有括号时:若为左括号,由于左括号直接入符号栈,所以入左括号进符号栈和入数进结果栈这两步操作的顺序无关紧要;若为右括号,那么该运算符后面就应该有一个数。如果该加号(或乘号)后面没有括号时,后面就该有一个数。辩证结束。

由于题目中要求的是最终表达式值为0的方案数,发现可由每次运算结果为0的方案数和结果为1的方案数推出: 设某运算符左边为1的方案数有l1种、为零的方案数有l0种;右边为1的方案数有r1种,右边为0的方案数有r0种。若该运算符为+,则结果为1的方案数则有l1*r1+l0*r1+l1*r2种,结果为0的方案数则有l0*r0种;若该运算符为*,则结果为1的方案数则有l1*r1种,结果为0的方案数则有l1*r0+l0*r0+l0*r1种。由此可以增设两个栈zero、one,分别维护随着结果栈进行运算时运算符左右两边为0的方案数和为1的方案数。思路就到此为止了。

见AC代码:

 #include<iostream>
#include<algorithm>
#include<cstdio>
#include<stack> using namespace std; int lenl; const int mod=; char exp[];//一开始输入的中缀表达式 string pol="n";//用'n'代替要填的数。pol为结果栈,但发现用string更好维护,于是就换成了string型。 stack<char> sta;//符号栈 stack<int>zero,one,ope;//zero、one的意义见上文,ope为计算后缀表达式时用到的辅助栈 int main()
{
cin>>lenl;
scanf("%s",exp);
for(int k=;k<lenl;k++)//中缀表达式转后缀表达式
{
if(exp[k]=='*'||exp[k]=='(')
sta.push(exp[k]);
if(exp[k]=='+')
{
while(!sta.empty()&&sta.top()=='*')
{
pol+='*';
sta.pop();
}
sta.push('+');
}
if(exp[k]==')')
{
while(sta.top()!='(')
{
pol+=sta.top();
sta.pop();
}
sta.pop();
}
if(exp[k]=='*'||exp[k]=='+') pol+='n';//填数
}
while(!sta.empty())//别忘了把符号栈剩余的元素转到结果里
{
pol+=sta.top();
sta.pop();
}
int l0,r0,l1,r1;
for(int k=;k<pol.length();k++)//计算后缀表达式
{
if(pol[k]=='n')
{
zero.push();
one.push();
}
if(pol[k]=='+')
{
l0=zero.top();zero.pop();
l1=one.top();one.top();
r0=zero.top();zero.pop();
r1=one.top();one.top();
zero.push(l0*r0%mod);
one.push(((l0*r1+l1*r0)%mod+l1*r1)%mod);
}
if(pol[k]=='*')
{
l0=zero.top();zero.pop();
l1=one.top();one.top();
r0=zero.top();zero.pop();
r1=one.top();one.top();
zero.push(((l0*r0+l1*r0)%mod+l0*r1)%mod);
one.push(l1*r1%mod);
}
}
cout<<zero.top();//最终使表达式值为零的方案数
return ;
}

做这个题时如果不会转中缀表达式转后缀表达式的话模拟也是可以骗点分的,但要注意考虑周全。(就算是一点微不足道的手误,也能造就90分到10分的神话(说多了都是泪))

洛谷P1310 表达式的值——题解的更多相关文章

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

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

  2. 洛谷P1310 表达式的值 题解 栈/后缀表达式的应用

    题目链接:https://www.luogu.org/problem/P1310 本题涉及算法:栈.前缀表达式转后缀表达式,动态规划思想. 这道题目我思考了好长时间,第一时间让我做的话我也做不出来. ...

  3. 洛谷 P1310 表达式的值 解题报告

    P1310 表达式的值 题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. "× "运算优先于"⊕"运算,即计算表 ...

  4. 洛谷P1310 表达式的值

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

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

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

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

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

  7. 洛谷 P1981 表达式求值

    P1981 表达式求值 题目描述 给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值. 输入输出格式 输入格式: 输入文件为 expr.in. 输入仅有一行,为需要你计算的表达式,表达式中只 ...

  8. 题解-洛谷P1981 表达式求值(模拟+处理优先级的递归)

    https://www.luogu.org/problemnew/show/P1981 (原题链接) 显然乘法的优先级高与加法,因此碰到乘号就要优先把一连串与乘号相连的数算出,很容易想到递归.可用普通 ...

  9. 洛谷 P5146 最大差值 题解

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

随机推荐

  1. 3D打印技术的学习

    1. 我们使用3D建模软件:123Ddesign来设计 123D design软件保存格式有2种,分别为123dx和stl格式 123dx格式:选择菜单栏中“Save”下的“To my compute ...

  2. HTML5实现绘制几何图形

    HTML5新增了一个<canvas.../>属性.该元素自身并不绘制图形,只是相当于一张空画布.如果开发者需要向<canvas.../>上绘制图形则必须使用JavaScript ...

  3. Centos7安装protobuf3.6.1

    简介 最近学习go语言,需要安装protobuf,但是网上的教程很多都不太适用于centos7 的系统.现在总结下protobuf在centos7下的安装教程. protobuf是Google开发出来 ...

  4. [DataContract]和[DataMember]缺少引用

    1.项目->右键->添加引用->找到System.Runtime.Serialization 2.代码中加上 Using System.Runtime.Serialization

  5. Android怎么改图标都不生效&&Android studio 如何修改APP图标和名字

    去这里(我自己写的),解决方法包你满意: https://blog.csdn.net/qq_43141611/article/details/101875545

  6. selenium 教程

    selenium 本身是一套web自动化测试工具,但其经常被用于爬虫,解决一些复杂爬虫的问题. selenium 用于爬虫时,相当于模拟人操作浏览器. 浏览器驱动 使用 selenium 需要先安装 ...

  7. Mysql数据库在建表时指定engine等于InnoDB 或MyISAM的意义

    一.ISAM和InnoDB的定义 1. ISAM ISAM是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到数据库被查询的次数要远大于更新的次数.因此,ISAM执行读取操作的速度很快 ...

  8. 封装class类--不分割类名

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  9. maven项目pom.xml报错: Failure to transfer org.apache.maven.plugins:maven-surefire-plugin:pom:2.7.1 from

    转自:https://blog.csdn.net/wolf1213hao/article/details/53413093

  10. c++ Socket客户端和服务端示例版本一

    客户端 #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <sys/soc ...