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

【题解】Luogu P1310 [NOIP 2011 普及组] 表达式的值

题意

给定一个仅包含与或的中缀表达式,在每一个数值位填 0 或 1,求有多少种填法使得表达式的值为 0。

思路

统计方案数,首先考虑 DP。要想得知表达式的值,就要得知参与最后运算的两个值。这启示我们将中缀转后缀,建表达式树。

定义 \(f_{u,0}\) 为以 \(u\) 为根的子树的表达式为 \(0\)\(f_{u,1}\) 同理。根据 \(u\) 的运算符列出状态转移方程。如果 \(u\) 是与,那么仅当两个子树表达式的值都为 \(1\) 时该表达式才为 \(1\)。根据乘法原理,方案数为 \(f_{lson,1}\times f_{rson,1}\)。其余依此类推。

\(u\) 为或:

\[f_{u,0}=f_{lson,0}\times f_{rson,0} \]

\[f_{u,1}=f_{lson,1}\times f_{rson,1}+f_{lson,0}\times f_{rson,1}+f_{lson,1}\times f_{rson,0} \]

\(u\) 为与:

\[f_{u,0}=f_{lson,0}\times f_{rson,0}+f_{lson,0}\times f_{rson,1}+f_{lson,1}\times f_{rson,0} \]

\[f_{u,1}=f_{lson,1}\times f_{rson,1} \]

答案即为 \(f_{root,0}\)。每个叶子结点都可以填 \(0\)\(1\),因此初始值都为 \(2\)

注意在补完表达式时要注意添加空位的情况,仅当运算符左边为括号时在左边添位,右边不为括号时在右边添位。为了方便添位和转后缀时的出栈,为表达式整体套一层括号。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#define int long long 
using namespace std;
const int N=1e5+10;
const int p=10007;
const int Tm=1e6+1,Ad=1e6+2,lKh=1e6+3,rKh=1e6+4;
int L,tot,totb,tott,cnt;
stack<int> st,st2;
char s[N];
int t[3*N],b[3*N];
int lson[3*N],rson[3*N],w[3*N],v[3*N];
int f[3*N][2];
void dfs(int u){if(lson[u]) dfs(lson[u]);if(rson[u]) dfs(rson[u]);if(w[u]==Ad){f[u][0]=f[lson[u]][0]*f[rson[u]][0]%p;f[u][1]=((f[lson[u]][0]*f[rson[u]][1]%p+f[lson[u]][1]*f[rson[u]][0]%p)%p+f[lson[u]][1]*f[rson[u]][1]%p)%p;}else if(w[u]==Tm){f[u][0]=((f[lson[u]][0]*f[rson[u]][1]%p+f[lson[u]][1]*f[rson[u]][0]%p)%p+f[lson[u]][0]*f[rson[u]][0]%p)%p;f[u][1]=f[lson[u]][1]*f[rson[u]][1]%p;}
}
signed main(){scanf("%lld",&L);scanf("%s",s+2);L+=2;s[1]='(';s[L]=')';for(int i=1;i<=L;i++){if(s[i]=='*'){if(t[tot]==lKh) t[++tot]=++cnt;t[++tot]=Tm;if(s[i+1]!='(') t[++tot]=++cnt;}else if(s[i]=='+'){if(t[tot]==lKh) t[++tot]=++cnt;t[++tot]=Ad;if(s[i+1]!='(') t[++tot]=++cnt;}else if(s[i]=='(') t[++tot]=lKh;else t[++tot]=rKh;}for(int i=1;i<=tot;i++){if(t[i]==Tm){while(!st.empty()&&st.top()==Tm){b[++totb]=Tm;st.pop();} st.push(Tm);}else if(t[i]==Ad){while(!st.empty()&&(st.top()==Tm||st.top()==Ad)){if(st.top()==Tm) b[++totb]=Tm;else b[++totb]=Ad;st.pop();}st.push(Ad);}else if(t[i]==rKh){while(!st.empty()&&st.top()!=lKh){if(st.top()==Tm) b[++totb]=Tm;else b[++totb]=Ad;st.pop();}if(!st.empty()) st.pop();}else if(t[i]==lKh) st.push(lKh);else b[++totb]=t[i];}for(int i=1;i<=totb;i++){if(b[i]<Tm){tott++;w[tott]=b[i];f[tott][0]=f[tott][1]=1;st2.push(tott);}else if(b[i]==Tm){int x=st2.top();st2.pop();int y=st2.top();st2.pop();lson[++tott]=x;rson[tott]=y;w[tott]=Tm;st2.push(tott);}else{int x=st2.top();st2.pop();int y=st2.top();st2.pop();lson[++tott]=x;rson[tott]=y;w[tott]=Ad;st2.push(tott);}}dfs(tott);printf("%lld\n",f[tott][0]);return 0;
} 

时间复杂度 \(O(L)\)

http://www.jsqmd.com/news/79205/

相关文章:

  • Java面试三连击:原理拆解+实战避坑
  • 【题解】Luogu P11854 [CSP-J2022 山东] 宴会
  • Stack
  • 深入Ascend C(四):多算子融合与图级优化实战——构建高性能Attention自定义Kernel
  • 【题解】Luogu P5322 [BJOI2019] 排兵布阵
  • 代码源挑战赛 Round 41
  • 详细介绍:NumPy / pandas 类型选型、内存占用与性能优化
  • 告别选择困难!2025年远程控制软件场景化终极横评
  • 一种可落地的任务令牌锁机制:设计原理、实战经验与容器化演进
  • [JSK]二叉苹果树
  • 【题解】Luogu P8137 [ICPC2020 WF] ’S No Problem
  • Day 36 官方文档的阅读
  • 青少年编程学习:考级与竞赛如何平衡
  • 2025 Autel MaxiVCI V150 Wireless Dongle: CAN FD/DOIP for Autel 900 Series Scanners
  • 【UI Qt】入门笔记
  • WSL安装方法
  • Ubuntu环境中LLaMA Factory 的部署与配置—构建大语言模型微调平台 - 实践
  • 2025贵阳公墓/公益公墓top5推荐!贵阳优质生态陵园榜单发布,合规保障与人文关怀兼具的安息之所推荐 - 全局中转站
  • 【题解】Luogu P2354 [NOI2014] 随机数生成器
  • 基于Django的农场管理系统
  • rsync交叉编译步骤
  • 下载UCI数据集《Secondary Mushroom》
  • 【题解】P11453 [USACO24DEC] Deforestation S
  • 03 以上版本 Excel 文件解压替换图片
  • 【题解】Luogu P13977 数列分块入门 2
  • AI核心知识50——大语言模型之Scaling Laws(简洁且通俗易懂版)
  • MySQL 深分页查询优化实践与经验总结
  • P2014 [CTSC1997] 选课
  • 彻底讲清 MySQL InnoDB 锁机制:从 Record 到 Next-Key 的全景理解
  • 超越宣传:基于数据与案例的软件人才外包服务商价值评估指南