Codeforces Round #465 (Div. 2)E. Fafa and Ancient Mathematics(CF935E)(树形动规)

树形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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值