题解:[CSP-J 2022] 逻辑表达式
题意分析
给定一个 bool 运算表达式,求其值和两种布尔短路在运算途中发生的次数。
首先,对于这种让你“计算表达式”的题目,一般来讲就是栈、递归。
然而我们看到这之中,“运算优先级”就十分的烦人。
我们可以考虑手动给给定的表达式添加括号,也可以考虑转后缀或前缀表达式进行运算。
我们同样可以使用栈来模拟, & 直接算,而 | 在有括号时才计算。
在本文,给出一种基于递归的的做法。
处理策略
(不会有人不知道 \(\land\) 是与,\(\lor\) 是或吧......)
对于给定表达式 \(a\),我们一定可以将其拆分为若干表达式 \(a[l_1,r_1],a[l_2,r_2],a[l_3,r_3],\cdots,a[l_p,r_p]\)。
我们定义 \(dfs(l,r)\) 表示 \(a[l,r]\) 的值。
比如说对于表达式 1&(2|3),\(a[1,7]\) 就是 1&(2|3),\(a[4,6]\) 就是 2|3。
对应地,\(dfs(1,7)=dfs(1,1)\land dfs(4,6)=1\land(2\lor3)=1\)。
那么,我们考虑 \(dfs(l,r)\) 内部怎么写。
首先,当 \(l,r\) 满足 \(l=r\) 时,无疑 \(dfs(l,r)=a_l=a_r\)。(无需考虑 \(a_l\) 是不是符号,是符号的话不会调用)
记 \(f_1[i],f_2[i]\) 分别为离 \(a_i\) 最近的同一层括号内 | 和 & 的位置。
那么当我们调用 \(dfs(l,r)\) 时,先判断 \(f_1[r],f_2[r]\) 的值是否在 \([l,r]\) 内,如果在,就说明需要进行计算。
以 \(\large a_{f_1[r]}\) 为例:
我们将 \(a[l,r]\) 拆分为两个表达式:\(a[l,f_1[r]-1]\lor a[f_1[r]+1,r]\),那么对应地就有递归式 \(dfs(l,r)=dfs(l,f_1[r]-1)\lor dfs(f_1[r]+1,r)\)。
这样我们就可以递归求解。(其实就是形如 \(a\land b\) 和 \(a\lor b\))。
如果 \(f_1[r],f_2[r]\) 的值都不合法,两种情况:
-
\(l=r\)。
-
\(a[l,r]\) 是形如 \((s)\) 的形式,其中 \(s\) 为合法表达式;那么显然此时有 \(dfs(l,r)=dfs(l+1,r-1)\)。
但是,注意不要将此条件放在 \(dfs(l,r)\) 的开始的同时判定条件写为
if(a[l]=='('&&a[r]==')')。因为,\(a[l,r]\) 同样也能形如 \((b)\land(c)\)。
AC 代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
const int N=1e6;
//1:|,2:&
int n,cnt1,cnt2,pl1[N+1],pl2[N+1],f1[N+1],f2[N+1];
char a[N];
void pre(){
static int pl1[N+1],pl2[N+1];
int pl=0;
for(int i=1;i<=n;i++){
switch(a[i]){
case '(':
pl++;
break;
case ')':
pl--;
break;
case '|':
pl1[pl]=i;
break;
case '&':
pl2[pl]=i;
break;
}//i之前最近的 |和 &(同层括号内)
f1[i]=pl1[pl];
f2[i]=pl2[pl];
}
}
bool dfs(int l,int r){
if(l==r)return a[l]^48;
//a|b
if(f1[r]>l){
bool ans=dfs(l,f1[r]-1);
if(ans){
cnt2++;
return true;
}return dfs(f1[r]+1,r);
}//a&b
else if(f2[r]>l){
bool ans=dfs(l,f2[r]-1);
if(!ans){
cnt1++;
return false;
}return dfs(f2[r]+1,r);
}//(a) -> a
if(a[l]=='('&&a[r]==')')return dfs(l+1,r-1);
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
scanf("%s",a+1);
n=strlen(a+1);
pre();
int ans=dfs(1,n);
printf("%d\n%d %d\n",ans,cnt1,cnt2);
/*fclose(stdin);
fclose(stdout);*/
return 0;
}

浙公网安备 33010602011771号