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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章