[CSP-J2020] 表达式 题解
1.P9748 [CSP-J 2023] 小苹果 题解2.P9749 [CSP-J 2023] 公路 题解3.P9751 [CSP-J 2023] 旅游巴士 题解4.P9750 [CSP-J 2023] 一元二次方程 题解5.P8813 [CSP-J 2022] 乘方 题解6.P8814 [CSP-J 2022] 解密 题解7.P8815 [CSP-J 2022] 逻辑表达式 题解8.P8816 [CSP-J 2022] 上升点列 题解9.P7909 [CSP-J 2021] 分糖果10.P7910 [CSP-J 2021] 插入排序 题解11.P7911 [CSP-J 2021] 网络连接 题解12.P7912 [CSP-J 2021] 小熊的果篮 题解13.P7071 [CSP-J2020] 优秀的拆分 题解14.P7072 [CSP-J2020] 直播获奖 题解
15.[CSP-J2020] 表达式 题解
16.P7074 [CSP-J2020] 方格取数 题解17.P5661 [CSP-J2019] 公交换乘 题解18.P5662 [CSP-J2019] 纪念品 题解19.P5663 [CSP-J2019] 加工零件 题解20.P5660 [CSP-J2019] 数字游戏 题解21.P11227 [CSP-J 2024] 扑克牌 题解22.P11228 [CSP-J 2024] 地图探险 题解23.P11229 [CSP-J 2024] 小木棍 题解24.P10124 [USACO18OPEN] Family Tree B 题解25.P9008 [入门赛 #9] 大碗宽面26.题解:AT_abc018_4 [ABC018D] バレンタインデー27.正规数的判定->题解28.逆波兰式->题解29.题解:P11372 「CZOI-R2」加训30.题解:AT_abc032_d [ABC032D] ナップサック問題31.题解:P11389 [COCI 2024/2025 #1] 等级 / Hijerarhija32.题解:B4070 [GESP202412 五级] 奇妙数字短路
这道题目中所含的运算符只有3个:与、或、非.
在与运算和或运算中有2个性质.
进行与运算时,若其中有一个值为0,则这个运算的结果就为0,即无需判断
另1个数是否是0或1.
进行或运算时,若其中有一个值为1,则这个运算的结果就为1,也无需判断
另一个数是否是0或1.
表达式树
根据短路的性质,可以得知,在与运算时,如果当前值为1,则需额外判断另
一个数是否为0,1,因为它的值可能会影响整个表达式的值.因此,需要构造一
棵表达式树.
其中,需要存储节点的编号,值,左孩子,右孩子.
染色
在递归的过程中,可以通过染色,判断这个节点对树的值是否有影响.
代码
#include<bits/stdc++.h> using namespace std; string s; int n, x[100005], cnt, num, c[100002], f[1000002]; int q, k; struct node { // 定义结构体 int id, v, lc, rc; // 编号,值,左孩子,右孩子 }t[1000002]; // tree stack<int> st; void post_to_tree() { // 转成表达式树的形式,以链式的方法存储 // !为-1,|为-2,&为-3 for (int i = 0; i < s.size(); i++) { if (s[i] == 'x') num = 0; // 如果说当前字符是x,则下一个字符一定是x的下表 else if (s[i] >= '0' && s[i] <= '9') num = num * 10 + (s[i] - '0'); // 用num存储下来下标的值 else if (s[i] == ' ') { if (s[i-1] >= '0' && s[i-1] <= '9') { // 上一个是下标 t[++cnt] = (node){cnt, num, -1, -1}; // lc, rc = -1, 表示没有 st.push(cnt); // 放入栈 } } else if (s[i] == '!') { int t1 = st.top();st.pop(); // 拿出栈顶元素 // 因为!为单目运算符,所以只要存左孩子就行了 t[++cnt] = (node){cnt, -1, t1, -1}; // 创建新节点 st.push(cnt); // 存编号 } else if (s[i] == '|') { // | 和 & 为双目运算符,所以要弹2个,并存左孩子和右孩子 int t1 = st.top();st.pop(); int t2 = st.top();st.pop(); t[++cnt] = (node){cnt, -2, t1, t2}; st.push(cnt); } else if (s[i] == '&') { int t1 = st.top();st.pop(); int t2 = st.top();st.pop(); t[++cnt] = (node){cnt, -3, t1, t2}; st.push(cnt); } } } bool calc_tree(int u) { // 计算树的原值 // 用f数组存值 if (t[u].v > 0) // 不是运算符 return f[u]=x[t[u].v]; // 在存入f数组中 if (t[u].v == -1) // ! return f[u]=!calc_tree(t[u].lc); // 这里千万不能直接或和与,因为根据短路性质,第2个值可能就不算了 if (t[u].v == -2) { // | bool f1 = calc_tree(t[u].lc); bool f2 = calc_tree(t[u].rc); return f[u] = f1 || f2; } // 这里分开算与或同理 if (t[u].v == -3) { // & bool f1 = calc_tree(t[u].lc); bool f2 = calc_tree(t[u].rc); return f[u] = f1 && f2; } } void solve_tree(int u) { if (t[u].v > 0) { // 如果是一个值,那可能会对值造成影响 c[t[u].v] = 1; // 进行染色 return ; } if (t[u].v == -1) // !运算递归染色 solve_tree(t[u].lc); if (t[u].v == -2) { // |运算 if (f[t[u].lc] == 0) solve_tree(t[u].rc); // 一个为0,则右边可能有短路 if (f[t[u].rc] == 0) solve_tree(t[u].lc); // 右边同理 } if (t[u].v == -3) { // &运算 if (f[t[u].lc] == 1) solve_tree(t[u].rc); // 一个为1,则左边可能有短路 if (f[t[u].rc] == 1) solve_tree(t[u].lc); // 右边同理 } } int main() { // freopen("expr2.in", "r", stdin); // freopen("expr2.out", "w", stdout); getline(cin, s); scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &x[i]); // 构建表达式树 post_to_tree(); // 计算原值 calc_tree(cnt); // 递归自己的改变是否影响原值 solve_tree(cnt); scanf("%d", &q); for (int i = 1; i <= q; i++) { scanf("%d", &k); if (c[k]) printf("%d\n", !f[cnt]); // 被染色,说明会影响原值,取反 else printf("%d\n", f[cnt]); } return 0; }
合集:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】