洛谷 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$ ...
随机推荐
- 【Spring】重新认识 IoC
前言 IoC (Inversion of control) 并不是Spring特有的概念. IoC 维基百科的解释: In software engineering, inversion of con ...
- 关于java socket中的read方法阻塞问题
客户端: public class TCPClient { public static void main(String[] args) throws IOException { FileInputS ...
- Redis:学习笔记-04
Redis:学习笔记-04 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 10. Redis主从复制 1 ...
- mybatis学习笔记(2)基本原理
引言在mybatis的基础知识中我们已经可以对mybatis的工作方式窥斑见豹(参考:<MyBatis----基础知识>).但是,为什么还要要学习mybatis的工作原理?因为,随着myb ...
- [no code][scrum meeting] Alpha 2
项目 内容 会议时间 2020-04-07 会议主题 功能规格说明书review 会议时长 30min 参会人员 OCR组(肖思炀,赵涛)和产品经理 $( "#cnblogs_post_bo ...
- 使用Mybatis的TypeHandler加解密数据
使用Mybatis的TypeHandler加解密数据 一.背景 二.解决方案 三.需求 四.实现思路 1.编写一个实体类,凡是此实体类的数据都表示需要加解密的 2.编写一个加解密的`TypeHandl ...
- 使用registry搭建docker私服仓库
使用registry搭建docker私服仓库 一.拉取 registry镜像 二.根据镜像启动一个容器 1.创建一个数据卷 2.启动容器 三.随机访问一个私服的接口,看是否可以返回数据 四.推送一个镜 ...
- 计算机网络之传输层UDP协议
文章转自:https://blog.csdn.net/weixin_43914604/article/details/105453096 学习课程:<2019王道考研计算机网络> 学习目的 ...
- Python爬取COVID-19疫情监控实战
一.项目概述 本项目基于Python.Flask.Echarts打造的一个疫情监控系统,涉及技术: Python网络爬虫 Python与Mysql数据库交互 使用Flask构建web项目 基于Echa ...
- NavigationView使用简介
Android支持直接创建带有NavigationView的Activity,这里主要介绍NavigationView的逻辑. NavigationView通常是跟DrawerLayout一起使用.D ...