树形DP。
将数字看做叶子节点,?(操作符)看做中间节点。
一开始没有看出来,还傻傻地想用背包将所有可能凑出的数字存下,其实只用知道最大值和最小值就行了。比较有的时候要用最大值减最小值来更新最大值。
看了这篇题解 才知道;
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int k=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){k=k*10+ch-'0';ch=getchar();}
return k*f;
}
inline void write(int x){
if(x<0)x=-x,putchar('-');
if(x>9)write(x/10);putchar(x%10+'0');
}
inline void writeln(int x){
write(x);puts("");
}
const int N = 20005,M = 105,inf = 1e9;
int rt,Mi[N][M],Mx[N][M],l[N],r[N],cnt;
int n,m,op,tmp;
char s[N];
void dfs(int &x,int &i){
i = ++cnt;
for(int j = 0;j <= n;++j) Mi[i][j] = inf,Mx[i][j] = -inf;
if(s[x] >= '0' && s[x] <= '9'){
Mx[i][0] = Mi[i][0] = s[x]-'0';
return;
}
dfs(++x,l[i]);
dfs(x += 2,r[i]);
++x;
for(int j = 0;j <= n;++j)
for(int k = 0;k <= j-(op^1);++k){
Mi[i][j] = min(Mi[i][j],Mi[l[i]][k]-Mx[r[i]][j-k-(op^1)]);
Mx[i][j] = max(Mx[i][j],Mx[l[i]][k]-Mi[r[i]][j-k-(op^1)]);
}
for(int j = 0;j <= n;++j)
for(int k = 0;k <= (j-(op^0));++k){
Mx[i][j] = max(Mx[i][j],Mx[l[i]][k]+Mx[r[i]][j-k-(op^0)]);
Mi[i][j] = min(Mi[i][j],Mi[l[i]][k]+Mi[r[i]][j-k-(op^0)]);
}
}
int main(){
scanf("%s",s+1);
m = strlen(s+1);
n = read(); tmp = read();
if(tmp < n){
swap(tmp,n);
op = 0;
}else op = 1;
tmp = 1;
dfs(tmp,rt);
printf("%d\n",Mx[rt][n]);
return 0;
}