题意:
给定一个长度为 E E E 的算式,格式为 d d d ( d d d 是个位数字) 或 ( E 1 o p E 2 ) ( E_1~op~E_2) (E1 op E2),其中 E 1 , E 2 E_1, E_2 E1,E2 均为算式, o p op op 为 + + + 或 − - −。在给定的算式中所有 o p op op 均未知,用问号替代,再给定 P P P 和 M M M,表示能填入的 + + + 和 − - − 的个数,求表达式的最大值,保证 P + M P + M P+M 等于问号数。 ( ∣ E ∣ ≤ 1 0 4 , m i n { P , M } ≤ 100 ) (|E| \leq 10^4, min\{P,M\} \leq 100) (∣E∣≤104,min{P,M}≤100)
链接:
https://codeforces.com/problemset/problem/935/E
解题思路:
所给的表达式为中缀表达式,可以用一棵二叉树表示。最大化表达式的值,用 d p dp dp 解决,考虑最后一个操作数,对于加法,需要最大化左右子树的值,减法则需要最大化左子树值、最小化右子树的值,故 m x [ u ] [ i ] [ j ] , m n [ u ] [ i ] [ j ] mx[u][i][j], mn[u][i][j] mx[u][i][j],mn[u][i][j] 分别维护 u u u 为根的子树使用 i i i 次加法、 j j j 次减法的最大、最小值,对应可以转移。注意 m i n { P , M } ≤ 100 min\{P, M\}\leq 100 min{P,M}≤100,数组可以只开较小的那一维,另一维可以隐式表示。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e4 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
vector<int> G[maxn];
char s[maxn];
int mx[maxn][101], mn[maxn][101];
int n, P, M;
int dfs(int &p){
if(isdigit(s[p])) return p++;
if(s[p] == '('){
int v1 = dfs(++p);
int u = p;
int v2 = dfs(++p);
G[u].pb(v1), G[u].pb(v2);
++p;
return u;
}
}
void dfs1(int u){
for(int i = 0; i <= P; ++i){
mx[u][i] = -inf;
mn[u][i] = inf;
}
if(s[u] != '?'){
mx[u][0] = mn[u][0] = s[u] - '0';
return;
}
int v1 = G[u][0], v2 = G[u][1];
dfs1(v1), dfs1(v2);
for(int i = 0; i <= P; ++i){
for(int j = P - i; j >= 0; --j){
mx[u][i + j] = max(mx[u][i + j], mx[v1][i] - mn[v2][j]);
mn[u][i + j] = min(mn[u][i + j], mn[v1][i] - mx[v2][j]);
if(i + j + 1 > P) continue;
mx[u][i + j + 1] = max(mx[u][i + j + 1], mx[v1][i] + mx[v2][j]);
mn[u][i + j + 1] = min(mn[u][i + j + 1], mn[v1][i] + mn[v2][j]);
}
}
}
void dfs2(int u){
for(int i = 0; i <= M; ++i){
mx[u][i] = -inf;
mn[u][i] = inf;
}
if(s[u] != '?'){
mx[u][0] = mn[u][0] = s[u] - '0';
return;
}
int v1 = G[u][0], v2 = G[u][1];
dfs2(v1), dfs2(v2);
for(int i = 0; i <= M; ++i){
for(int j = M - i; j >= 0; --j){
mx[u][i + j] = max(mx[u][i + j], mx[v1][i] + mx[v2][j]);
mn[u][i + j] = min(mn[u][i + j], mn[v1][i] + mn[v2][j]);
if(i + j + 1 > M) continue;
mx[u][i + j + 1] = max(mx[u][i + j + 1], mx[v1][i] - mn[v2][j]);
mn[u][i + j + 1] = min(mn[u][i + j + 1], mn[v1][i] - mx[v2][j]);
}
}
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
cin >> s + 1 >> P >> M;
int p = 1, rt = dfs(p);
if(P < M){
dfs1(rt);
cout << mx[rt][P] << endl;
}
else{
dfs2(rt);
cout << mx[rt][M] << endl;
}
// for(int i = 1; s[i]; ++i){
// if(s[i] == '(' || s[i] == ')') continue;
// for(int j = 0; j <= P; ++j){
// cout << i << " " << s[i] << " " << j << " " << mx[i][j] << " " << mn[i][j] << endl;
// }
// }
return 0;
}