题目链接  Codeforces Round #465 (Div. 2) Problem E

题意  给定一个表达式,然后用$P$个加号和$M$个减号填充所有的问号(保证问号个数等于$P + M$)

   求可以形成的表达式的最大值。

先把表达式转成一棵树,然后在树上DP。

题目保证了$min(P, M) <= 100$, 为了提高效率,我们选择用少的运算符号作为DP的第二维。

对$P$和$M$的大小关系进行分类讨论。

当$P < M$时,

设$f[i][j]$表示$i$代表的子树里面填$j$个加号能得到的结果的最大值。

$c[i][j]$表示$i$代表的子树里面填$j$个减号能得到的结果的最小值。

那么转移就是

$f[x][i+j+1] = max(f[x][i+j+1], f[l][i] + l[r][j])$

$f[x][i+j] = max(f[x][i+j], f[l][i] - c[r][j])$

$c[x][i+j+1] = min(c[x][i+j+1], c[l][i] + c[r][j])$

$c[x][i+j] = min(c[x][i+j], c[l][i] - f[r][j])$

当$P > M$时,

设$f[i][j]$表示$i$代表的子树里面填$j$个加号能得到的结果的最大值。

$c[i][j]$表示$i$代表的子树里面填$j$个减号能得到的结果的最小值。

设个时候转移方程为

$f[x][i+j] = max(f[x][i+j], f[l][i] + l[r][j])$

$f[x][i+j+1] = max(f[x][i+j+1], f[l][i] - c[r][j])$

$c[x][i+j] = min(c[x][i+j], c[l][i] + c[r][j])$

$c[x][i+j+1] = min(c[x][i+j+1], c[l][i] - f[r][j])$

程序里把两种情况合起来写了,看起来更加简洁。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second typedef long long LL; const int N = 1e4 + 10;
const int M = 105;
const int inf = 1e9; char st[N];
int val[N];
int p, m, n;
int f[N][M], c[N][M];
vector <int> v[N];
stack <int> stk; inline void upmax(int &a, int b){ a = max(a, b);}
inline void upmin(int &a, int b){ a = min(a, b);} void dfs(int x, int t){
rep(i, 0, M - 1) f[x][i] = -inf, c[x][i] = inf;
if (val[x]){
f[x][0] = c[x][0] = val[x];
return;
} int l = v[x][0], r = v[x][1];
dfs(l, t), dfs(r, t); rep(i, 0, M - 1) if (f[l][i] > -inf){
rep(j, 0, M - 1) if (f[r][j] > -inf){
upmax(f[x][i + j + t], f[l][i] + f[r][j]);
upmax(f[x][i + j + (t ^ 1)], f[l][i] - c[r][j]);
upmin(c[x][i + j + t], c[l][i] + c[r][j]);
upmin(c[x][i + j + (t ^ 1)], c[l][i] - f[r][j]);
}
}
} int main(){ scanf("%s%d%d", st, &p, &m); for (int i = 0; st[i]; ++i){
if (st[i] == '(') stk.push(++n);
else if (st[i] == ')'){
int t = stk.top();
stk.pop();
if (!stk.empty()) v[stk.top()].push_back(t);
} else if (st[i] >= '1' && st[i] <= '9'){
if (stk.empty()) return 0 * printf("%d\n", st[i] - '0');
v[stk.top()].push_back(++n);
val[n] = st[i] - '0';
}
} dfs(1, p < m);
printf("%d\n", f[1][min(p, m)]);
return 0;
}

  

最新文章

  1. ActiveMQ(li)
  2. CSS Hack技术介绍及常用的Hack技巧集锦
  3. Android性能优化
  4. H5基于iScroll实现下拉刷新,上拉加载更多
  5. 数据结构图文解析之:直接插入排序及其优化(二分插入排序)解析及C++实现
  6. hive相关
  7. 一个平台BUG,好吧,找到了一个新的办法,同样的效果
  8. CentOS下LAMP一键yum安装脚本
  9. java 后台校验格式
  10. 两种方式判断类的存在→className getAttribute
  11. 利用concat进行数组复制
  12. MVC缓存,使用数据层缓存,添加或修改时让缓存失效
  13. C#三种方式实现序列化(转)
  14. display:inline-block的运用
  15. 一些常见warning的原因和解决方法
  16. Android ContentProvider详解
  17. Technical debt
  18. Linux获取网络接口信息
  19. Hadoop3.0 WordCount测试一直Accept 状态,Nodes of the cluster 页面node列表个数为0
  20. Redis in .NET Core 入门:(4) LIST和SET

热门文章

  1. 《Cracking the Coding Interview》——第12章:测试——题目4
  2. USACO Section1.5 Number Triangles 解题报告
  3. 浅谈 css 之 position用法
  4. python之列表/元组/字典/字符串
  5. Python全栈工程师(文件操作、编码)
  6. centos6 install cobbler
  7. Ubuntu下禁用笔记本自带键盘
  8. 通过命令行安装或卸载Tomcat服务
  9. ubuntu16.04 使用问题笔记
  10. PHP生成随机数函数rand(min,max)