CSP-J 2022_第三题逻辑表达式

题目

逻辑表达式是计算机科学中的重要概念和工具,包含逻辑值、逻辑运算、逻辑运算优先级等内容。
在一个逻辑表达式中,元素的值只有两种可能:0(表示假)和 1(表示真)。元素之间有多种可能的逻辑运算,本题中只需考虑如下两种:“与”(符号为 &)和“或”(符号为 |)。其运算规则如下:
0&0=0&1=1&0=0,1&1=1;
0∣0=0,0∣1=1∣0=1∣1=1。
在一个逻辑表达式中还可能有括号。规定在运算时,括号内的部分先运算;两种运算并列时,& 运算优先于 | 运算;同种运算并列时,从左向右运算。
比如,表达式 0|1&0 的运算顺序等同于 0|(1&0);表达式 0&1&0|1 的运算顺序等同于 ((0&1)&0)|1。
此外,在 C++ 等语言的有些编译器中,对逻辑表达式的计算会采用一种“短路”的策略:在形如 a&b 的逻辑表达式中,会先计算 a 部分的值,如果 a=0,那么整个逻辑表达式的值就一定为 0,故无需再计算 b 部分的值;同理,在形如 a|b 的逻辑表达式中,会先计算 a 部分的值,如果 a=1,那么整个逻辑表达式的值就一定为 1,无需再计算 b 部分的值。
现在给你一个逻辑表达式,你需要计算出它的值,并且统计出在计算过程中,两种类型的“短路”各出现了多少次。需要注意的是,如果某处“短路”包含在更外层被“短路”的部分内则不被统计,如表达式 1|(0&1) 中,尽管 0&1 是一处“短路”,但由于外层的 1|(0&1) 本身就是一处“短路”,无需再计算 0&1 部分的值,因此不应当把这里的 0&1 计入一处“短路”。

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

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

输入输出样例
输入 #1
0&(1|0)|(1|1|1&0)
输出 #1
1
1 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
【数据范围】

设 ∣s∣ 为字符串 s 的长度。

对于所有数据,1≤∣s∣≤10
6
。保证 s 中仅含有字符 0、1、&、|、(、) 且是一个符合规范的逻辑表达式。保证输入字符串的开头、中间和结尾均无额外的空格。保证 s 中没有重复的括号嵌套(即没有形如 ((a)) 形式的子串,其中 a 是符合规范的逻辑表达式)。
在这里插入图片描述
其中:
特殊性质 1 为:保证 s 中没有字符 &。
特殊性质 2 为:保证 s 中没有字符 |。
特殊性质 3 为:保证 s 中没有字符 ( 和 )。

【提示】

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

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

代码

#include <bits/stdc++.h>//万能头文件,包含c++标准库中常用头文件 
using namespace std;//使用std命名空间,使用标准库中类型、函数时无需std::前缀 
int n_yu,n_huo; //与和或运算短路次数 
struct node{//二叉树节点类型 char x;//操作符号'&'、'|'、'('、')' 、'0'、'1' bool k;//各逻辑运算结果 node *fa, *left, *right;//指向父、左、右节点的指针 node() : x('*'),fa(nullptr), left(nullptr), right(nullptr) {}//默认构造函数,初始化节点 node(char cx){//带参构造函数,根据字符初始化节点 x=cx,fa=nullptr, left=nullptr, right=nullptr;if(cx=='1'||cx=='0')k=cx-'0';}
};
class Tree{public:node *root,*current;    // 根节点指针,当前操作节点指针(构建树时用)// 构造函数:初始化根节点和当前节点Tree(){//构造函数,构造根节点为'r'(不变),当前节点指向根 root=new node('r'), current=root;}~Tree() {// 析构函数:递归释放整个语法树节点内存clear(root);root = current = nullptr;}void insert(char x) {//根据字符类型,插入并构建语法树     node* newNode = new node(x);// 创建新节点if(x=='0'||x=='1'||x=='('){//操作数和左括号 newNode->fa = current;//成为当前节点的子节点 if(!current->left)current->left = newNode;//当前节点左子节点空,就挂到左节点 else if(!current->right)current->right = newNode;//否则挂右节点 }else if(x==')'){//右括号时要归拢,调整当前位置回到左括号处 current=current->fa;//下句无法越过当前的左括号,添加该句主动升一层 while(current->x!='(')current=current->fa;//循环一直找到左括号位置 newNode->fa=current;current->right=newNode;//左括号节点的右节点是右括号 newNode=newNode->fa;//左括号调整为当前节点位置 }else if(x=='|'){//优先级在|和&下,当前位置升到紧邻左括号或者根前 while(current->fa->x!='('&&current->fa!=root)current=current->fa;current->fa->left=newNode;newNode->fa=current->fa;//|变成当前节点父节点的左子, current->fa=newNode;newNode->left=current;//当前节点变成|的左子 }else if(x=='&'){//如果父节点是|,则&优先级高,要下潜。否则遇到&就得上浮 if(current->fa->x=='|'){current->fa->right=newNode;newNode->fa=current->fa;//当前节点的父节点变成&的父节点, current->fa=newNode;newNode->left=current;//当前节点变成&节点的左节点 }else{while(current->fa->x=='&')current=current->fa;//父是&就得上浮,得父不是&得节点为当前节点 if(current->fa->left==current)current->fa->left=newNode;//当前节点是父节点的左子,挂父节点的左树 else current->fa->right=newNode;//挂父节点的右树 newNode->fa=current->fa;current->fa=newNode;newNode->left=current;//当前节点(&)挂插入节点的左树 }}current=newNode;//插入的节点变成当前节点(括号选左括号) }void clear(node* x) {// 递归清除节点及其子节点if (!x) return;clear(x->left);clear(x->right);delete x;}void view1(node *x){cout<<x->x;if(x->left)view1(x->left);if(x->right)view1(x->right);}void view3(node *x){if(x->left)view3(x->left);cout<<x->x;if(x->right)view3(x->right);}void view2(node *x){cout<<x->x<<"["<<x->k<<"] ";if(x->left)view2(x->left);if(x->right)view2(x->right);}bool run(node *n){bool k1,k2; //左右树运算结果 if(n->x=='r')return n->k=run(n->left);//根和左括号处结果仅源自左树 if(n->x=='(')return n->k=run(n->left);//右括号不影响结果 if(n->x=='0'||n->x=='1')return n->k;//运算数 if(n->x=='&'){//与运算 k1=run(n->left);//先算左树 if(k1==0){//如果左树是0,直接返回0,不用算右树 n_yu++;return n->k=0;}k2=run(n->right);return n->k=k1&&k2;}if(n->x=='|'){//或运算 k1=run(n->left);if(k1==1){//如果左树是1,直接返回1,不用算右树 n_huo++;return n->k=1;}k2=run(n->right);return n->k=k1||k2;}}
}tree;
int main(){//freopen("expr.in","r",stdin);string s;cin>>s;for(int i=0;s[i];i++){tree.insert(s[i]); //cout<<i<<" "<<s[i]<<"先序";tree.view1(tree.root);cout<<endl;}//cout<<"先序";tree.view1(tree.root);cout<<endl;//cout<<"中序";tree.view3(tree.root);cout<<endl;cout<<tree.run(tree.root)<<endl;cout<<n_yu<<" "<<n_huo<<endl;//cout<<"先序";tree.view2(tree.root);cout<<endl;return 0;
}

思路

1.构建二叉树,n个字符n次操作,)、|和&需要上溯,最差情况是从当前节点回溯到根节点(n次),所以时间复杂度是o(n^2),这里n=10 ^6,结果是10 ^12,大于1秒的大约次数10 ^8次。有可能会超时——还好没有。
遍历逻辑表达式,每个字符建立一个指针空间节点
将所有节点连接成二叉树
经过一些样例数据的实操,得到逻辑关系
root
开始就有,用r标记,位置不变。后继只有左没有右
0、1、(
添(节点,或左或右
)
上溯,找到(节点,成为(节点的右节点,父(成当前节点。
先回溯一次,避免连续右括号时停留在当前(节点
|
添节点
上溯,直到父是根r或(,当前节点变成自己的左节点,自己成父的右节点
&
添节点
父是|,则当前节点(0、1)成为自己的左节点,自己成父(|)的右节点
父是&,则上溯直到父是|或者根或(,当前节点成左节点,自己成父的右节点
2.递归计算。run函数,,先左右再根,后序遍历,至多每个节点算一次O(n)。
return k=run(left)&&run(right);感觉只算左(不知道原因)
须要分别计算
k1=run(left)
k2=run(right)
&运算,左是0是短路。|运算左是1是短路。(当然另一边也存在这种情况,但是本题说了只是左)
有10^6个节点

作图验证

在这里插入图片描述

小结

冬麦需要9个月,夏玉米需要4个月。万事万物的生长成熟都需要足够的时间!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/90957.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/90957.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从释永信事件看“积善“与“积恶“的人生辩证法

博客目录起心动念皆是因&#xff0c;当下所受皆是果。"起心动念皆是因&#xff0c;当下所受皆是果。"这句古老的智慧箴言&#xff0c;在少林寺方丈释永信涉嫌违法被调查的事件中得到了令人唏嘘的印证。一位本应六根清净、持戒修行的佛门领袖&#xff0c;却深陷贪腐丑…

图片格式转换

文章目录 背景目标实现下载 背景 格式碎片化问题 行业标准差异&#xff1a;不同领域常用格式各异&#xff08;如设计界用PSD/TIFF&#xff0c;网页用JPG/PNG/WEBP&#xff0c;系统图标用ICO/ICNS&#xff09;。 设备兼容性&#xff1a;老旧设备可能不支持WEBP&#xff0c;专业…

Flutter实现Android原生相机拍照

方法1&#xff1a;使用Flutter的camera插件&#xff08;完整实现&#xff09; 1. 完整依赖与权限配置 # pubspec.yaml dependencies:flutter:sdk: fluttercamera: ^0.10.52path_provider: ^2.0.15 # 用于获取存储路径path: ^1.8.3 # 用于路径操作permission_handler:…

记录几个SystemVerilog的语法——随机

1. 随机稳定性(random stability)随机稳定性是指每个线程(thread)或对象(object)的random number generator(RNG)是私有的&#xff0c;一个线程返回的随机值序列与其他线程或对象的RNG是无关的。随机稳定性适用于以下情况&#xff1a;系统随机方法调用&#xff1a;$urandom()和…

初识 docker [下] 项目部署

项目部署Dockerfile构建镜像DockerCompose基本语法基础命令项目部署 前面我们一直在使用别人准备好的镜像&#xff0c;那如果我要部署一个Java项目&#xff0c;把它打包为一个镜像该怎么做呢&#xff1f; …省略一万字 站在巨人的肩膀上更适合我们普通人,所以直接介绍两种简单…

Android15广播ANR的源码流程分析

Android15的广播ANR源码流程跟了下实际代码的流程&#xff0c;大概如下哈&#xff1a;App.sendBroadcast() // 应用发起广播→ AMS.broadcastIntentWithFeature() // 通过Binder IPC进入system_server进程→ AMS.broadcastIntentLocked() // 权限校验广播分类&#xff08;前…

密码学中的概率论与统计学:从频率分析到现代密码攻击

在密码学的攻防博弈中&#xff0c;概率论与统计学始终是破解密码的“利器”。从古典密码时期通过字母频率推测凯撒密码的密钥&#xff0c;到现代利用线性偏差破解DES的线性密码分析&#xff0c;再到侧信道攻击中通过功耗数据的统计特性还原密钥&#xff0c;统计思维贯穿了密码分…

力扣刷题977——有序数组的平方

977. 有序数组的平方 题目&#xff1a; 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,10] 输出&#xff1a;[0,1,9,16,100] 解释&…

应用加速游戏盾的安全作用

在数字娱乐产业蓬勃发展的今天&#xff0c;游戏已从单纯的娱乐工具演变为连接全球数十亿用户的社交平台与文化载体。然而&#xff0c;伴随游戏市场的指数级增长&#xff0c;网络攻击的频率与复杂性也呈爆发式上升。从DDoS攻击导致服务器瘫痪&#xff0c;到外挂程序破坏公平竞技…

linux安装zsh,oh-my-zsh,配置zsh主题及插件的方法

这是一份非常详细的指南&#xff0c;带你一步步在 Linux 系统中安装 Zsh、配置主题和安装插件。 Zsh&#xff08;Z Shell&#xff09;是一个功能强大的 Shell&#xff0c;相比于大多数 Linux 发行版默认的 Bash&#xff0c;它提供了更强的自定义能力、更智能的自动补全、更漂亮…

【设计模式系列】策略模式vs模板模式

策略模式是什么&#xff1f;如何定义并封装一系列算法策略模式 (Strategy Pattern)模板模式 (Template Pattern)模板模式与策略模式的深度对比与区分混合使用两种模式的场景策略模式 (Strategy Pattern) 应用场景&#xff1a;当需要根据不同条件选择不同算法或行为时&#xff…

aigc(1.1) opensora-2.0

open sora-2.0相关链接: arxiv链接 huggingface页面 HunyuanVideo VAE open sora2.0的VAE模型复用了HunyuanVideo的3D VAE,HunyuanVideo的arxiv链接。下图来自论文,可见VAE是一个因果注意力的3D结构。在配图左侧,视频会被编码为video token序列,而在配图右侧,去噪的vide…

Linux驱动21 --- FFMPEG 音频 API

目录 一、FFMPEG 音频 API 1.1 解码步骤 创建核心上下文指针 打开输入流 获取输入流 获取解码器 初始化解码器 创建输入流指针 创建输出流指针 初始化 SDL 配置音频参数 打开音频设备 获取一帧数据 发送给解码器 从解码器获取数据 开辟数据空间 初始化内存 音频重采样…

《计算机“十万个为什么”》之 [特殊字符] 序列化与反序列化:数据打包的奇妙之旅 ✈️

《计算机“十万个为什么”》之 &#x1f4e6; 序列化与反序列化&#xff1a;数据打包的奇妙之旅 ✈️欢迎来到计算机“十万个为什么”系列&#xff01; 本文将以「序列化与反序列化」为主题&#xff0c;深入探讨计算机世界中数据的打包与解包过程。 让我们一起解开数据的神秘面…

机器学习与深度学习评价指标

机器学习与深度学习评价指标完全指南 📊 为什么需要评价指标? 想象你是一位医生,需要判断一个诊断模型的好坏。如果模型说"这个病人有癌症",你需要知道: 这个判断有多准确? 会不会漏掉真正的癌症患者? 会不会误诊健康的人? 评价指标就像是给AI模型打分的&…

Hugging Face-环境配置

打开anaconda promptconda activate pytorchpip install -i https://pypi.tuna.tsinghua.edu.cn/simple transformers datasets tokenizerspycharm找到pytorch下的python.exe#将模型下载到本地调用 from transformers import AutoModelForCausalLM,AutoTokenizer#将模型和分词工…

cnn中池化层作用

一、池化层概述 在卷积神经网络中&#xff0c;池化层是核心组件之一&#xff0c;主要作用是逐步降低特征图的空间尺寸即宽和高&#xff0c;从而减少计算量、控制过拟合并增强模型的鲁棒性。 核心作用 降维与减少计算量 压缩特征图的尺寸&#xff0c;显著减少后续层的参数数量和…

写一个音乐爬虫

今天我们写一个网易云音乐的爬虫&#xff0c;爬取网易云音乐热歌榜音乐链接并下载&#xff0c;这里用到了之前引用的BeautifulSoup和requests。 BeautifulSoup是一个Python库&#xff0c;用于从HTML和XML文件中提取数据。它提供了一种简单的方式来遍历文档树和搜索文档树中的元…

战斗公式和伤害走配置文件

故事背景&#xff0c;上次属性计算用的配置&#xff0c;这次伤害计算也走配置&#xff0c;下面是测试代码和测试数据local formulas {[100001]{id 100001,name "基础伤害",formula "function (self,tag,ishit,iscritial,counterratio)\n if ishit1 then\n …

线性代数 上

文章目录线性代数知识整理一、求行列式1、 套公式2、利用性质&#xff0c;化为可套公式3、抽象行列式4、抽象向量二、代数余子式的线性组合三、求AnA^nAn四、证明A可逆五、求A的逆1、定义法2、初等变换3、公式六、求秩七、线性表示的判定八、线性无关九、求极大线性无关组十、等…