CSP-J2022-C-逻辑表达式题解
题意:给你一个由
0
、1
、&
、|
、(
、)
组成的字符串,保证是一个合法的逻辑表达式。其中括号优先级最高,与运算优先级高于或运算,同级之间从左到右算。定义一次短路为,或运算的左边结果为 1,或者与运算的左边结果为 0,此时后面部分无需计算(也不统计短路)。询问该逻辑表达式的结果以及与、或运算各自的短路次数。
做法 1
我们可以先使用栈预处理出括号的匹配(分段),然后使用 DFS 来计算。
DFS 时传入当前要处理的区间,返回该区间的结果,通过 DFS 内更改全局变量统计短路次数。对于区间之间的转移,我们有以下两种处理方法:
1.1
考虑最后一次运算的位置。从最右边开始,每次往前跳一段,如果出现或运算则一定是最后一次,否则继续跳;如果没有或运算则为最后一次与运算的位置。有了这个,我们递归地计算出从开头到最后一次的位置的答案,判断是否短路。如果不短路,则递归右边计算。这个做法显然会超时,因为可能会重复地扫同层之间的与运算。所以我们传参时传入一个布尔参数 ,表示是否能确定当前层没有或运算。如果 ,则可以直接跳过“每次跳一段”的过程,直接得出最后一次操作的位置。复杂度显然正确。
By myself
1 |
|
1.2
也和上个类似,寻找最后一次运算位置作为分段点。这个做法用较高的代码难度换了较低的思维难度,直接使用 ST 表来预处理分段位置。
By GD-J00096
1 |
|
1.3
同层之间直接从左往右跳,每一段递归计算。缺点是需要处理与或的优先级问题,优点是复杂度直接就是正确的,思维难度较低。
By JS-J00401
1 |
|
1.4
考虑暴力分层,对于每层直接建一个段跳跃的链表,每层之间递归处理,简化思维难度。
By GD-J01245
1 |
|
做法 2
考虑直接从左到右扫,实时维护。具体维护上,也有两种方法:
2.1
预处理的加强版。此做法预处理的不仅是括号的匹配,还有计算顺序的匹配,即完整地分段。例如,0&1|1&(1|1&1)
会将 0&1
、1&(1|1&1)
分别在首尾匹配上(相当于暴力加括号,但并不会真的加上而是维护匹配),此时再从左往右扫即可不分优先级地处理答案。
By JS-J00426
1 |
|
2.2
此做法不需要预处理,甚至不需要开栈。考虑从左往右扫,直接维护答案。如果发生短路,则暴力跳过后面的一段。这个做法的关键在于,只要不发生短路,答案一定取决于后面而与前面完全无关。这个做法中甚至几乎不用处理括号和优先级,因为括号和优先级仅起到分割块的作用,在暴力跳一段时才需要考虑。
By JS-J00837
1 |
|