当前位置: 首页 > news >正文

【P8815 [CSP-J 2022] 逻辑表达式】

题目:P8815 [CSP-J 2022] 逻辑表达式

题目描述

逻辑表达式是计算机科学中的重要概念和工具,包含逻辑值、逻辑运算、逻辑运算优先级等内容。

在一个逻辑表达式中,元素的值只有两种可能:000(表示假)和 111(表示真)。元素之间有多种可能的逻辑运算,本题中只需考虑如下两种:“与”(符号为 &)和“或”(符号为 |)。其运算规则如下:

0&0=0&1=1&0=00 \mathbin{\&} 0 = 0 \mathbin{\&} 1 = 1 \mathbin{\&} 0 = 00&0=0&1=1&0=01&1=11 \mathbin{\&} 1 = 11&1=1
0∣0=00 \mathbin{|} 0 = 000=00∣1=1∣0=1∣1=10 \mathbin{|} 1 = 1 \mathbin{|} 0 = 1 \mathbin{|} 1 = 101=10=11=1

在一个逻辑表达式中还可能有括号。规定在运算时,括号内的部分先运算;两种运算并列时,& 运算优先于 | 运算;同种运算并列时,从左向右运算。

比如,表达式 0|1&0 的运算顺序等同于 0|(1&0);表达式 0&1&0|1 的运算顺序等同于 ((0&1)&0)|1

此外,在 C++ 等语言的有些编译器中,对逻辑表达式的计算会采用一种“短路”的策略:在形如 a&b 的逻辑表达式中,会先计算 a 部分的值,如果 a=0a = 0a=0,那么整个逻辑表达式的值就一定为 000,故无需再计算 b 部分的值;同理,在形如 a|b 的逻辑表达式中,会先计算 a 部分的值,如果 a=1a = 1a=1,那么整个逻辑表达式的值就一定为 111,无需再计算 b 部分的值。

现在给你一个逻辑表达式,你需要计算出它的值,并且统计出在计算过程中,两种类型的“短路”各出现了多少次。需要注意的是,如果某处“短路”包含在更外层被“短路”的部分内则不被统计,如表达式 1|(0&1) 中,尽管 0&1 是一处“短路”,但由于外层的 1|(0&1) 本身就是一处“短路”,无需再计算 0&1 部分的值,因此不应当把这里的 0&1 计入一处“短路”。

输入格式

输入共一行,一个非空字符串 sss 表示待计算的逻辑表达式。

输出格式

输出共两行,第一行输出一个字符 01,表示这个逻辑表达式的值;第二行输出两个非负整数,分别表示计算上述逻辑表达式的过程中,形如 a&ba|b 的“短路”各出现了多少次。

输入输出样例 #1

输入 #1

0&(1|0)|(1|1|1&0)

输出 #1

1
1 2

输入输出样例 #2

输入 #2

(0|1&0|1|1|(1|1))&(0&1&(1|0)|0|1|0)&0

输出 #2

0
2 3

说明/提示

【样例解释 #1】

该逻辑表达式的计算过程如下,每一行的注释表示上一行计算的过程:

0&(1|0)|(1|1|1&0)
=(0&(1|0))|((1|1)|(1&0)) //用括号标明计算顺序
=0|((1|1)|(1&0))   //先计算最左侧的 &,是一次形如 a&b 的“短路”
=0|(1|(1&0))       //再计算中间的 |,是一次形如 a|b 的“短路”
=0|1               //再计算中间的 |,是一次形如 a|b 的“短路”
=1

【样例 #3】

见附件中的 expr/expr3.inexpr/expr3.ans

【样例 #4】

见附件中的 expr/expr4.inexpr/expr4.ans

【数据范围】

∣s∣\lvert s \rverts 为字符串 sss 的长度。

对于所有数据,1≤∣s∣≤1061 \le \lvert s \rvert \le {10}^61s106。保证 sss 中仅含有字符 01&|() 且是一个符合规范的逻辑表达式。保证输入字符串的开头、中间和结尾均无额外的空格。保证 sss 中没有重复的括号嵌套(即没有形如 ((a)) 形式的子串,其中 a 是符合规范的逻辑表达式)。

测试点编号∣s∣≤\lvert s \rvert \les特殊条件
1∼21 \sim 212333
3∼43 \sim 434555
5552000200020001
6662000200020002
7772000200020003
8∼108 \sim 10810200020002000
11∼1211 \sim 121112106{10}^61061
13∼1413 \sim 141314106{10}^61062
15∼1715 \sim 171517106{10}^61063
18∼2018 \sim 201820106{10}^6106

其中:
特殊性质 1 为:保证 sss 中没有字符 &
特殊性质 2 为:保证 sss 中没有字符 |
特殊性质 3 为:保证 sss 中没有字符 ()

【提示】

以下给出一个“符合规范的逻辑表达式”的形式化定义:

  • 字符串 01 是符合规范的;
  • 如果字符串 s 是符合规范的,且 s 不是形如 (t) 的字符串(其中 t 是符合规范的),那么字符串 (s) 也是符合规范的;
  • 如果字符串 ab 均是符合规范的,那么字符串 a&ba|b 均是符合规范的;
  • 所有符合规范的逻辑表达式均可由以上方法生成。

理解

经过对数据的推演,大量反思总结出生成二叉树的规则
在这里插入图片描述
1.建立二叉树
2.每个节点都有父和左右子节点
3.从根root开始,需要当前位置cur
4.(0|1&0|1|1|(1|1))&(0&1&(1|0)|0|1|0)&0
都先建立节点now
5.0、1
成为当前节点cur的左,有左就右
6.(
成为cur的左,有左就右
自己成为cur
7.)
一直上溯到(,并成为其右树,
(父变成cur
8.&
一直上溯到非&,并记住where从哪里上溯
where是左自己就是左,否则右
where变成自己左
9.|
一直上溯到非&、非|,同样记住where
where是左就是左,否则右
远where变成左

代码

#include <bits/stdc++.h>
using namespace std;
struct node{//二叉树节点 char c;//运算符bool k;//布尔值node *f,*l,*r;//父节点,左右子节点node(){c='*',f=l=r=NULL;} //无参构造 node(char x){c=x,f=l=r=NULL,k=(c=='1');}//有参构造 
}root;//二叉树根
void add(node *f,node *c){//子节点c挂到f的左,有左就右 c->f=f;if(!f->l)f->l=c;else f->r=c;
} 
void view(node *x){//后序遍历,逆波兰表达式,天然有序,无需考虑优先级 if(x->l)view(x->l);if(x->r)view(x->r);if(x->c!='('||x->c!=')')cout<<x->c;
}
string s;//输入的运算符 
bool ans;//逻辑运算结果 
int he_and=0,he_or=0;//从左运算,“短路”的数量 
bool go(node *x){//从根开始运算 if(x->c=='0'||x->c=='1')return x->c=='1';//直接返回0、1 bool k1,k2;//左右分支的运算结果 if(x->l)k1=go(x->l);//有左就算左 if(x->c=='|'&&k1==1){he_or++;return 1;}//或短路 if(x->c=='&'&&k1==0){he_and++;return 0;}//与短路 if(x->c!='('&&x->r)k2=go(x->r);//无短路就算右分支 if(x->c=='|')return k1||k2;//或运算 else if(x->c=='&')return k1&&k2;//与运算 else if(x->c=='('||x->c=='*')return k1;//单分支 
}
int main(){//freopen("data.cpp","r",stdin);node *cur=&root;//开始时根就是当前节点,一直记住当前节点 cin>>s;//优先级高潜里,否则浮上(0|1&0|1|1|(1|1))&(0&1&(1|0)|0|1|0)&0 for(int i=0;i<s.length();i++){//遍历每个字符 node *now=new node(s[i]);//每个字符都建立节点,对应现在指针 if(s[i]=='('){add(cur,now);cur=now;}//挂到当前节点,后自己时当前节点 else if(s[i]==')'){while(cur->c!='(')cur=cur->f;//上浮,一直找到(父 add(cur,now);cur=cur->f;//挂到当前节点,收括号后上浮一层 }else if(s[i]=='&'){node *child;//确定上浮自左右哪个分支 if(cur->r)child=cur->r;//有有节点就是右 else child=cur->l;//否则就是左 while(cur->c=='&')child=cur,cur=cur->f;//只比&优先级低,唯遇到&上浮 now->f=cur;//挂当前节点 if(cur->l==child)cur->l=now;//替代child的分支,就是挂当前节点的左右哪个 else cur->r=now;add(now,child);cur=now;//把原先的child挂到自己左节点 }else if(s[i]=='|'){node *child;if(cur->r)child=cur->r;else child=cur->l;while(cur->c=='&'||cur->c=='|')child=cur,cur=cur->f;//只比|和&优先级低 now->f=cur;if(cur->l==child)cur->l=now;else cur->r=now;add(now,child);cur=now;}else add(cur,now);//加0、1数值 }//view(&root); cout<<endl;ans=go(&root);//运算,并统计“短路”数 cout<<ans<<"\n"<<he_and<<" "<<he_or; return 0;
}

时间复杂度

1.建树过程中,每个字符执行一次节点创建、指针调整等操作,单次是O(1),所以总复杂度是O(n)。
2.递归函数(完成逻辑运算)也是恰好遍历一次每个节点,所以复杂度也是O(n)。

http://www.dtcms.com/a/471470.html

相关文章:

  • 有哪些网站做二手房好的做网站怎么维护
  • 网站做漏洞扫描费用wordpress批量添加摘要
  • 路由器通过域名解析做网站用asp做的几个大网站
  • 进行网站推广有哪些常用方法企业建站电话多少
  • 邯郸 网站建设中国交通建设集团有限公司地址
  • 编译原理机测客观题(2)词法分析
  • 大型建设网站网站优化总结
  • 中国铁路建设投资公司官方网站wordpress什么环境
  • 如何自建网站 卖东西自己的电脑做服务器,并建网站
  • 智能手机网站模板建建建设网站公司电话号码
  • 第四章 神经网络的基本组件
  • 百度不收录新网站手机网站优化
  • 手机网站源码 html5网站建设与维护的不足
  • 德鲁克管理哲学:管理是知行统一的实践创新
  • 做场景秀的网站电子商城网站建设费用
  • **标题:发散创新:探究TPU架构的深度解析**在现代计算领域,TPU(Tensor Processing Unit)架构以其
  • 郑州做网站的专业公司西安做网站哪家比较好
  • 网站建设与维护服务器学习网站开发
  • Facebook受众挖掘的高效方法
  • 怎么建自己的摄影网站我的世界怎么做购买点卷网站
  • CasADi mpc
  • 六盘水网站开发北京度seo排名
  • Linux小课堂: 文件系统结构与核心命令解析
  • 做京东网站需要哪些手续费濮阳网站建设知名公司排名
  • 辽宁城市建设职业技术学院教育网站wordpress搭建软件下载
  • 营销型网站案例专题页面设计模板
  • Coze源码分析-资源库-编辑数据库-前端源码-核心组件
  • 如何创建一个论坛网站海南省交通建设局网站首页
  • 2025年生物学、农业与污染控制技术国际会议(BAPCT 2025)
  • 【全志V821_FoxPi】6-3 GC2083 MIPI摄像头适配