洛谷 P7324 - [WC2021] 表达式求值(状压+dp)
现场人傻系列……
首先建出 \(E\) 的表达式树,具体来说表达式的每一个叶子节点表示一个数组 \(A_i\),每一个非叶子节点都表示一次运算,它的值表示左右儿子进行该运算后得到的结果。这个可以通过建表达式树的套路方法在 \(\mathcal O(|E|)\) 的时间内求出来。
其次注意到数组每一位的贡献是独立的,也就是说我们可以对 \(n\) 位每一位都单独求一遍贡献。于是现在等价于我们解决 \(n\) 个如下的问题:
- 给出一个数组 \(a_1,a_2,\cdots,a_m\) 和一个带问号的表达式 \(E\),其中 \(E\) 有些位置是 \(<\),有些位置是 \(>\),有些位置是 \(?\),你可以将 \(?\) 替换为 \(<\) 或 \(>\),求所有可能得到的表达式的值之和。
这个问题显然可以用树形 \(dp\) 求解,设 \(dp_{i,j}\) 表示执行完表达式树上 \(i\) 子树中所有运算后,得到的值为 \(a_j\) 的填法,转移就分该节点上的运算为 \(<\) 和 \(>\) 转移即可,相当于求一遍 \(\max/\min\) 卷积,时间复杂度 \(n|E|m^2\),当然如果想用前缀和优化可以做到 \(n|E|m\),反正都是暴力,过不去。
考虑优化,注意到 \(n\),也就是子问题个数很多,但是数组长度 \(m\) 非常非常小,并且每次运算的表达式都是一样的。我们考虑借鉴 CF878D 的套路,对每种可能的相对数组大小计算一遍贡献,不过直接枚举相对大小有 \(m!\) 种,再乘上表达式长度 \(5\times 10^4\),还是会 TLE。考虑对上面的子问题进行转化,对于一个子问题我们将这个子问题对应的 \(a\) 数组从小到大排个序,设为 \(b_1,b_2,\cdots,b_m\),显然最终任意一个表达式运算的结果一定出自这 \(m\) 个数,对于一个运算结果为 \(b_i\) 的表达式,我们不直接加上 \(b_i\) 的贡献,instead 我们用差分的思想,显然 \(\forall j\le i,b_i\ge b_j\),也就是说我们可以对于所有 \(i\) 统计运算得到的结果 \(\ge b_i\) 的表达式个数 \(c_i\),并令答案加上 \((b_i-b_{i-1})\times c_i\),不难发现这样算下来每种运算结果为 \(b_i\) 的表达式会产生 \((b_i-b_{i-1})+(b_{i-1}-b_{i-2})+\cdots+(b_1-b_0)=b_i\) 的贡献,符合题意。
我们考虑怎样统计运算得到的结果 \(\ge b_i\) 的表达式个数,我们回到原来的 \(a\) 数组,记 \(c_j=[a_j\ge b_i]\),对于一种表达式,我们将 \(c\) 数组带回到表达式进行运算,如果运算结果为 \(1\) 那么真正的运算结果 \(\ge b_i\),反之真正的运算结果 \(<b_i\),正确性显然。这样转化有什么好处呢?不难发现这样一转化,所有数都缩小到了 \([0,1]\) 范围内,可能的情况个数也就降到了 \(2^m\),于是我们对这 \(2^m\) 分别预处理一遍即可,即 \(f_{S}\) 为当 \(\forall x\in S,c_x=1,\forall x\notin S,c_x=0\) 时有多少个表达式运算得到的值为 \(1\),对于每个 \(S\) 显然可以在 \(\mathcal O(|E|)\) 内求出 \(f_S\),那么如果我们记 \(ST_i\) 为 \(\{j|a_j\ge b_i\}\),那么运算得到的结果 \(\ge b_i\) 的表达式个数为 \(f_{ST_i}\)。把 \(a\) 排个序后随便搞搞就好了,时间复杂度 \(|E|2^m+mn\log m\)。
const int MAXM=10;
const int MAXN=5e4;
const int MAXP=1<<10;
const int MOD=1e9+7;
int n,m,len,a[MAXM+5][MAXN+5],mch[MAXN+5];char s[MAXN+5];
int ch[MAXN*2+5][2],op[MAXN*2+5],ncnt=0,rt=0;
ll dp[MAXN*2+5][2],f[MAXP+5];pii p[MAXM+5];
int build(int l,int r){
int id=++ncnt;
if(l==r) return op[id]=s[l]-'0',id;
if(s[r]==')'){
if(mch[r]==l) id=build(l+1,r-1);
else{
op[id]=(s[mch[r]-1]=='<')?10:((s[mch[r]-1]=='>')?11:12);
ch[id][0]=build(l,mch[r]-2);
ch[id][1]=build(mch[r],r);
}
} else {
op[id]=(s[r-1]=='<')?10:((s[r-1]=='>')?11:12);
ch[id][0]=build(l,r-2);
ch[id][1]=build(r,r);
}
return id;
}
void dfs(int x,int st){
if(!ch[x][0]&&!ch[x][1]){dp[x][~st>>op[x]&1]=1;return;}
dfs(ch[x][0],st);dfs(ch[x][1],st);
if(op[x]!=10){
dp[x][0]=(dp[x][0]+1ll*dp[ch[x][0]][0]*dp[ch[x][1]][0])%MOD;
dp[x][1]=(dp[x][1]+1ll*dp[ch[x][0]][1]*dp[ch[x][1]][0]+1ll*dp[ch[x][0]][0]*dp[ch[x][1]][1]+1ll*dp[ch[x][0]][1]*dp[ch[x][1]][1])%MOD;
} if(op[x]!=11){
dp[x][1]=(dp[x][1]+1ll*dp[ch[x][0]][1]*dp[ch[x][1]][1])%MOD;
dp[x][0]=(dp[x][0]+1ll*dp[ch[x][0]][1]*dp[ch[x][1]][0]+1ll*dp[ch[x][0]][0]*dp[ch[x][1]][1]+1ll*dp[ch[x][0]][0]*dp[ch[x][1]][0])%MOD;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
scanf("%s",s+1);len=strlen(s+1);stack<int> st;
for(int i=1;i<=len;i++){
if(s[i]=='(') st.push(i);
if(s[i]==')') mch[i]=st.top(),st.pop();
} rt=build(1,len);
for(int i=0;i<(1<<m);i++){
memset(dp,0,sizeof(dp));dfs(rt,i);
f[i]=dp[rt][1];//printf("%d %d\n",i,f[i]);
} int ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<m;j++) p[j]=mp(a[j][i],j);
sort(p,p+m);int msk=0;
for(int j=0;j<m;j++){
ans=(ans+1ll*f[msk]*(p[j].fi-p[j-1].fi))%MOD;
msk|=(1<<p[j].se);
}
} printf("%d\n",ans);
return 0;
}
洛谷 P7324 - [WC2021] 表达式求值(状压+dp)的更多相关文章
- P7324 [WC2021] 表达式求值
P7324 [WC2021] 表达式求值 闲话 WC2021 我只得了 20 分,三道题总共 20 分.我是下场了突然后知后觉这件事的,主要原因是我开了 C++11,然后 T1 T2 都没分了.在洛谷 ...
- 【题解】洛谷P2704 [NOI2001] 炮兵阵地(状压DP)
洛谷P2704:https://www.luogu.org/problemnew/show/P2704 思路 这道题一开始以为是什么基于状压的高端算法 没想到只是一道加了一行状态判断的状压DP而已 与 ...
- 【题解】洛谷P1896 [SCOI2005] 互不侵犯(状压DP)
洛谷P1896:https://www.luogu.org/problemnew/show/P1896 前言 这是一道状压DP的经典题 原来已经做过了 但是快要NOIP 复习一波 关于一些位运算的知识 ...
- 洛谷P1171 售货员的难题【状压DP】
题目描述 某乡有n个村庄(1 输入格式: 村庄数n和各村之间的路程(均是整数). 输出格式: 最短的路程. 输入样例: 3 0 2 1 1 0 2 2 1 0 输出样例 3 说明 输入解释 3 {村庄 ...
- 洛谷 P2622 关灯问题II【状压DP】
传送门:https://www.luogu.org/problemnew/show/P2622 题面: 题目描述 现有n盏灯,以及m个按钮.每个按钮可以同时控制这n盏灯--按下了第i个按钮,对于所有的 ...
- UOJ #129 / BZOJ 4197 / 洛谷 P2150 - [NOI2015]寿司晚宴 (状压dp+数论+容斥)
题面传送门 题意: 你有一个集合 \(S={2,3,\dots,n}\) 你要选择两个集合 \(A\) 和 \(B\),满足: \(A \subseteq S\),\(B \subseteq S\), ...
- 2018.07.18 洛谷P1171 售货员的难题(状压dp)
传送门 感觉是一道经典的状压dp,随便写了一发卡了卡常数开了个O(2)" role="presentation" style="position: relati ...
- 洛谷P2761 软件补丁问题(状压dp)
传送门 啊咧……这题不是网络流二十四题么……为啥是个状压dp…… 把每一个漏洞看成一个状态,直接硬上状压dp 然后因为有后效型,得用spfa //minamoto #include<iostre ...
- 洛谷$P3226\ [HNOI2012]$集合选数 状压$dp$
正解:$dp$ 解题报告: 传送门$QwQ$ 考虑列一个横坐标为比值为2的等比数列,纵坐标为比值为3的等比数列的表格.发现每个数要选就等价于它的上下左右不能选. 于是就是个状压$dp$板子了$QwQ$ ...
随机推荐
- 初学python写个自娱自乐的小游戏
一.摘要 当编写完后的代码执行第一次后达到了目标的预期效果,内心有些许满足,但是当突发情况产生后,程序便不能正常运行,于是准备从简单的版本开始出发,综合考虑使用者的需求,和使用过程中会遇到的问题,一步 ...
- 天脉2(ACoreOS653)操作系统学习01
天脉2(ACoreOS653)操作系统学习01 由于我的毕业设计涉及相关嵌入式操作系统,故最近学了学天脉2操作系统. 一.ARINC653标准 1.ARINC653标准是什么? ARINC 653 : ...
- [敏捷软工团队博客]Beta阶段发布声明
项目 内容 2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 Beta阶段发布声明 我们在这个课程的目标是 在团队合作中锻炼自己 这个作业在哪个具体方面帮助我们实现目标 对Bet ...
- 常用JAVA API :HashSet 和 TreeSet
set容器的特点是不包含重复元素,也就是说自动去重. HashSet HashSet基于哈希表实现,无序. add(E e)//如果容器中不包含此元素,则添加. clear()//清空 contain ...
- Java并发:Condition接口
Condition 接口与 Lock 配合实现了等待 / 通知模式,这个和 Object 的监视器方法(wait.notify.notifyAll 等方法)一样,都是实现了等待 / 通知模式,但这两者 ...
- 密码学基础:AES加密算法
[原创]密码学基础:AES加密算法-密码应用-看雪论坛-安全社区|安全招聘|bbs.pediy.com 目录 基础部分概述: 第一节:AES算法简介 第二节:AES算法相关数学知识 素域简介 扩展域简 ...
- c#复制数组的多种方法
方法一:使用for循环 int []pins = {9,3,7,2} int []copy = new int[pins.length]; for(int i =0;i!=copy.length;i+ ...
- 前端面试手写代码——call、apply、bind
1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...
- Java 17 新功能介绍(LTS)
点赞再看,动力无限.Hello world : ) 微信搜「程序猿阿朗 」. 本文 Github.com/niumoo/JavaNotes 和 未读代码博客 已经收录,有很多知识点和系列文章. Jav ...
- 【pycharm】Python pip升级及升级失败解决方案,报错:You are using pip version 10.0.1, however version 21.3.1 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' command.
我已经升级到了最新的版本 安装其他模块过程中出现下面提示,便说明你需要升级pip You are using pip version 10.0.1, however version 21.3.1 is ...