习题:Fafa and Ancient Mathematics(树DP&转换问题)

题目

传送门

思路

一个括号其实就相当于一个子树

也就是这是一个树形DP的题

这题的难点也在于转换,DP并不是很难

\(dp[i][j][0/1]\)表示以i为根节点的子树,用了j的\(-/+\)之后的最大/最小值

用类似于背包的方程去转移其即可

代码

#include<iostream>
#include<cstring>
using namespace std;
char a[100005];
int dp[100005][105][2];//用加号作为限制,0/1:最小值&最大值
int f[100005][105][2];//用减号作为限制,0/1:最小值&最大值
int lena;
int limit,p,m;
int tre[10005][2],cnt,pre,fa[10005];
void dfs(int u)
{
    if(tre[u][0]==0)
        return;
    dfs(tre[u][0]);
    dfs(tre[u][1]);
    //cout<<u<<' '<<tre[u][0]<<endl;
    //cout<<u<<' '<<tre[u][1]<<endl;
    for(int i=0;i<=limit;i++)
    {
        for(int j=0;j<=i;j++)
        {
            //处理加号
            dp[u][i+1][0]=min(dp[u][i+1][0],dp[tre[u][0]][j][0]+dp[tre[u][1]][i-j][0]);
            dp[u][i][0]=min(dp[u][i][0],dp[tre[u][0]][j][0]-dp[tre[u][1]][i-j][1]);
            dp[u][i+1][1]=max(dp[u][i+1][1],dp[tre[u][0]][j][1]+dp[tre[u][1]][i-j][1]);
            dp[u][i][1]=max(dp[u][i][1],dp[tre[u][0]][j][1]-dp[tre[u][1]][i-j][0]);
            //处理减号
            f[u][i][0]=min(f[u][i][0],f[tre[u][0]][j][0]+f[tre[u][1]][i-j][0]);
            f[u][i+1][0]=min(f[u][i+1][0],f[tre[u][0]][j][0]-f[tre[u][1]][i-j][1]);
            f[u][i][1]=max(f[u][i][1],f[tre[u][0]][j][1]+f[tre[u][1]][i-j][1]);
            f[u][i+1][1]=max(f[u][i+1][1],f[tre[u][0]][j][1]-f[tre[u][1]][i-j][0]);
        }   
    }
}
int main()
{
    ios::sync_with_stdio(false);
    for(int i=0;i<=10000;i++)
    {
        for(int j=0;j<=100;j++)
        {
            f[i][j][0]=dp[i][j][0]=(1<<25);
            f[i][j][1]=dp[i][j][1]=-(1<<25);
        }
    }
    cin>>(a+1);
    lena=strlen(a+1);
    cin>>p>>m;
    limit=min(p,m);
    cnt=pre=1;
    for(int i=1;i<=lena;i++)
    {
        if(a[i]=='('||a[i]=='?')
        {
            tre[pre][tre[pre][0]?1:0]=++cnt;
            fa[cnt]=pre;
            pre=cnt;
        }
        else if(a[i]==')')
            pre=fa[pre];
        else
        {
            dp[cnt][0][0]=dp[cnt][0][1]=a[i]-'0';
            f[cnt][0][0]=f[cnt][0][1]=a[i]-'0';
            pre=fa[pre];
        }
    }
    dfs(1);
    if(p<m)
        cout<<dp[1][p][1];
    else
        cout<<f[1][m][1];
    return 0;
}
posted @ 2020-07-31 12:15  loney_s  阅读(120)  评论(0)    收藏  举报