【学术篇】CF935E Fafa and Ancient Mathematics 树形dp
前言
这是一道cf的比赛题..
比赛的时候C题因为自己加了一个很显然不对的特判WA了7次但找不出原因就弃疗了...
然后就想划水, 但是只做了AB又不太好... 估计rating会掉惨 (然而事实证明rating一点没变)
就去看看别的题,, 但是英语不好, 看题要看半天, 看看这个E题题目名称像是数论?(mmp估计是受到了古代猪文的影响). 点进去没仔细读题好像是个等价表达式一样的题目? 好像很麻烦还1h不写了(没错C题细节各种挂调了好久好久, 当时已经是很绝望了OvO)
结果这题tm是个dp...
题意
英文题一定要有的一个部分... 毕竟
这么长时间不学, 还会说英语吗? ——wcg
所以还是要翻译一下...
就是给一个运算符都被扣掉的表达式, 让你往里面填\(P\)个\(+\)和\(M\)个\(-\), 求最大的可能的结果.
表达式中的数字都是一位数, 而且每一层运算都套了一个括号, (这样才比较方便处理, 其实麻烦一点也能处理但是...)
分析
显然地, 我们可以把表达式画成一棵树. 以第四组样例为例, 我们可以画出一棵这样的树:
然后怎么建树啊, 我们知道这棵树肯定是从底往上建的, 所以我们要利用一种神奇的, 叫"栈"的数据结构.
我们用一个临时变量tmp来储存等待着父亲的左儿子. 这个左儿子可能是一个数, 也可能是一个点. 为了方便起见, 我们让点的标号从11开始(因为数字只有一位...那你说为什么不用10呢?).
- 当我们扫到一个数字的时候, 把tmp设置为这个数字.
- 当我们扫到一个?的时候, 我们建立一个新节点(其实就是++tot就行了), 将tmp作为他的左儿子, 右儿子先留空.
然后将其入栈, 表示接下来的一个右儿子应该去找它. - 当我们遇到一个)的时候, 我们将tmp作为栈顶元素的右儿子. 然后将tmp设置为栈顶元素, 栈顶元素出栈.
发现自己并不能解释清楚为什么要这么搞... 自己画画图体会一下吧OvO.
建好树后我们来设计状态:
- 令\(f[x][i]\)表示在以\(x\)为根的子树中使用了\(i\)个\(+\)得到的最大值
- 由于有-的存在, 我们令\(g[x][i]\)表示在以\(x\)为根的子树中国使用了\(i\)个\(+\)得到的最小值
然后我们就记忆化搜索一波, 枚举\(+\)的个数做就行了, 对于当前节点:
这个节点是个数字? 直接返回咯~
两个儿子都是数字? 直接算咯~
填\(+\):
f[x][i]=max{f[lson[x]][j]+f[rson[x]][i-j-1]},j=0..i-1
左右两儿子都取最大时和最大
g[x][i]=min{g[lson[x]][j]+g[rson[x]][i-j-1]}
左右两儿子都取最小时和最小填\(-\):
f[x][i]=max{f[lson[x]][j]-g[rson[x]][i-j-1]}
左儿子取最大, 右儿子取最小时差最大
g[x][i]=min{g[lson[x]][j]-f[rson[x]][i-j-1]}
左儿子取最小, 右儿子取最大时差最小.
这样就做完了(假的), 时间复杂度\(O(n*P)\), 可能会过不了.
而且空间复杂度也是\(O(n*P)\)的, 数组应该开不开..
但是呢\(min(P,M)\leq100\), 这样我们就可以分类讨论一下, 然后用上面的做法只枚举较少的那个符号...
这样时空复杂度就都能过辣...
代码(写的有点丑,没怎么压行,calcMax和calcMin基本是一样的...):
#include <cctype>
#include <cstdio>
#include <cstring>
const int INF=1000000007;
inline int max(const int &a,const int &b){return a>b?a:b;}
inline int min(const int &a,const int &b){return a<b?a:b;}
int t[5015][2],f[5005][102],g[5005][102],sz[5005];
int stk[5005],tp,cur,tot=10,rt;
char str[10010]; bool now;
void dfssz(int x){ //用子树中包含运算符的个数来排除一部分不合法状态.
sz[x]=1;
if(t[x][0]>10) dfssz(t[x][0]),sz[x]+=sz[t[x][0]];
if(t[x][1]>10) dfssz(t[x][1]),sz[x]+=sz[t[x][1]];
}
void init(){ //建树
memset(f,192,sizeof(f));
memset(g,127,sizeof(g));
int l=strlen(str),fa;
for(int i=0;i<l;++i){
if(isdigit(str[i]))
cur=str[i]-'0';
if(str[i]=='?'){
stk[++tp]=++tot;
t[tot][0]=cur;
}
if(str[i]==')'){
fa=stk[tp--];
t[fa][1]=cur;
cur=rt=fa;
}
}
dfssz(rt);
}
int calcMax(int x,int p);
int calcMin(int x,int p){
if(p<0||p>sz[x]) return INF;
if(x<10) return x;
if(sz[x]==1) return now==(bool)p?t[x][0]+t[x][1]:t[x][0]-t[x][1];
if(g[x][p]<INF) return g[x][p];
int mn=min(sz[t[x][0]],p),ans1,ans2;
for(int i=0;i<=mn;++i){
ans1=calcMin(t[x][0],i)+calcMin(t[x][1],p-now-i); //+
ans2=calcMin(t[x][0],i)-calcMax(t[x][1],p+now-1-i); //-
g[x][p]=min(g[x][p],min(ans1,ans2));
}
return g[x][p];
}
int calcMax(int x,int p){
if(p<0||p>sz[x]) return -INF;
if(x<10) return x;
if(sz[x]==1) return now==(bool)p?t[x][0]+t[x][1]:t[x][0]-t[x][1];
if(f[x][p]>-INF) return f[x][p];
int mn=min(sz[t[x][0]],p),ans1,ans2;
for(int i=0;i<=mn;++i){
ans1=calcMax(t[x][0],i)+calcMax(t[x][1],p-now-i); //+
ans2=calcMax(t[x][0],i)-calcMin(t[x][1],p+now-1-i); //-
f[x][p]=max(f[x][p],max(ans1,ans2));
}
return f[x][p];
}
int main(){
scanf("%s",str);
if(strlen(str)==1){puts(str);return 0;}
init();
int a,b; scanf("%d%d",&a,&b);
if(a<b) now=1; else now=0; //now用来标记+多还是-多
printf("%d",calcMax(rt,now?a:b));
}
过了一个假期颓成狗了... 代码都不会写了快...
啊啊啊啊啊下午还要测试怎么办啊~
【学术篇】CF935E Fafa and Ancient Mathematics 树形dp的更多相关文章
- CodeForces 935E Fafa and Ancient Mathematics (树形DP)
题意:给定一个表达式,然后让你添加 n 个加号,m 个减号,使得表达式的值最大. 析:首先先要建立一个表达式树,这个应该很好建立,就不说了,dp[u][i][0] 表示 u 这个部分表达式,添加 i ...
- Codeforces 935E Fafa and Ancient Mathematics dp
Fafa and Ancient Mathematics 转换成树上问题dp一下. #include<bits/stdc++.h> #define LL long long #define ...
- Codeforces 935E Fafa and Ancient Mathematics(表达式转树 + 树型DP)
题目链接 Codeforces Round #465 (Div. 2) Problem E 题意 给定一个表达式,然后用$P$个加号和$M$个减号填充所有的问号(保证问号个数等于$P + M$) ...
- 【学术篇】一些水的不行的dp
最近做了几道非常水非常水的dp...... 之后刷的一些水dp也会写在这里...... 此篇题目难度不递增!!! Emmmm....... 1.luogu1043数字游戏 以前看过这个题几遍,没做这个 ...
- NOIP2011pj表达式的值[树形DP 笛卡尔树 | 栈 表达式解析]
题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算.例如:计算表达式A⊕B × ...
- CF 337D Book of Evil 树形DP 好题
Paladin Manao caught the trail of the ancient Book of Evil in a swampy area. This area contains n se ...
- 动态规划——树形dp
动态规划作为一种求解最优方案的思想,和递归.二分.贪心等基础的思想一样,其实都融入到了很多数论.图论.数据结构等具体的算法当中,那么这篇文章,我们就讨论将图论中的树结构和动态规划的结合——树形dp. ...
- Day1:T3 bfs T4 树形DP
T3:BFS 回看了一下Day1的T3...感觉裸裸的BFS,自己当时居然没有看出来... 同时用上升和下降两种状态bfs即可 这一题还要注意一个细节的地方,就是题目要求的是求往返的最优解 k=min ...
- HDU5758 Explorer Bo 思维+树形dp
题意自己看题目吧,挺短的. 思考过程:昨天感觉一天不做题很对不起自己,于是晚上跑到实验室打开别人树形dp的博客做了上面最后一个HDU的题,也是个多校题..一开始没有头绪了很久,因为起点不固定,所以这1 ...
随机推荐
- 挂载时出现mount: RPC: Unable to receive; errno = Connection refused错误的解决方法
当我们在做NFS开发板下挂载时,经常会出现mount: RPC: Unable to receive; errno = Connection refused的错误,连接被拒绝了,到底是什么原因呢? 这 ...
- 从Airbnb的发展历程和网易云的大起大落看IT行业创新(第5周课后作业)
我想先根据个人看法回答“创新是什么?”这个空泛的问题.创新是面对当下的资源条件限制创造出能够满足动态需求或解决动态发展中的问题的新策略.这种实用化定义在大部分邻域都勉强能让定义者自圆其说,对于IT行业 ...
- css雪碧图(精灵图)与字体图标的介绍以及对比
css雪碧图(精灵图)与字体图标的介绍以及对比 设想一个实际场景:在一个页面为了展示,我们放置了很多独立的小图片,浏览器在显示页面的时候,就需要向服务器就会发送很多请求,来获取并加载这些小图片,但是这 ...
- 2018-8-10-win10-uwp-DataContext-
title author date CreateTime categories win10 uwp DataContext lindexi 2018-08-10 19:16:53 +0800 2018 ...
- 【学术篇】CF833B TheBakery 分治dp+主席树
题目の传送门~ 题目大意: 将\(n\)个蛋糕分成恰好\(k\)份, 求每份中包含的蛋糕的种类数之和的最大值. 这题有两种做法. 第一种是线段树优化dp, 我还没有考虑. 另一种就是分治+主席树. 然 ...
- 小白的第一篇python博客
学习python课程三天,先了解了计算机的历史及各种发展史,python的历史及部分语法,python主要学习内容有"hello world",int常量.str字符串,print ...
- python爬虫(2):图片,翻译爬虫
import urllib.request#urllib.request.urlopen可以传入url或者Request对象#req=urllib.request.Request("http ...
- vue组件参数校验与非props特性
组件参数校验 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <ti ...
- c# 转16进制
1.byte[] 转换16进制字符串 1.1 BitConverter方式 var str = DateTime.Now.ToString(); var encode = Encoding.UTF8; ...
- Redis Cluster集群详介绍和伪集群搭建
1 什么是Redis-Cluster 为何要搭建Redis集群.Redis是在内存中保存数据的,而我们的电脑一般内存都不大,这也就意味着Redis不适合存储大数据,适合存储大数据的是Hadoop生态系 ...