题解:
树形dp
要记录一个最小的,一个最大的
然后转移
代码:
#include<bits/stdc++.h> using namespace std; const int N=10005; int p,m,g[N*2][105],f[N*2][105],T[N*2][2],size[N*2],num; char s[N*2]; int build(int x,int y) { if (x==y) { num++; f[num][0]=g[num][0]=s[x]-'0'; return num; } int l=0; for (int i=x;i<=y;i++) { if (s[i]=='(')l++; if (s[i]==')')l--; if (s[i]=='?'&&l==1) { int l=build(x+1,i-1),r=build(i+1,y-1); num++; T[num][0]=l;T[num][1]=r; size[num]=size[l]+size[r]+1; return num; } } } void dfs(int x) { if (!T[x][0]&&!T[x][1])return; dfs(T[x][0]);dfs(T[x][1]); int l=T[x][0],r=T[x][1]; if (p<m) { for (int i=0;i<=p;i++) for (int j=0;j<=i;j++) if (j<=size[l]&&i-j<=size[r]) g[x][i]=min(g[x][i],g[l][j]-f[r][i-j]); for (int i=0;i<=p;i++) for (int j=0;j<i;j++) if (j<=size[l]&&i-j-1<=size[r]) g[x][i]=min(g[x][i],g[l][j]+g[r][i-j-1]); for (int i=0;i<=p;i++) for (int j=0;j<=i;j++) if (j<=size[l]&&i-j<=size[r]) f[x][i]=max(f[x][i],f[l][j]-g[r][i-j]); for (int i=0;i<=p;i++) for (int j=0;j<i;j++) if (j<=size[l]&&i-j-1<=size[r]) f[x][i]=max(f[x][i],f[l][j]+f[r][i-j-1]); } else { for (int i=0;i<=m;i++) for (int j=0;j<=i;j++) if (j<=size[l]&&i-j<=size[r]) g[x][i]=min(g[x][i],g[l][j]+g[r][i-j]); for (int i=0;i<=m;i++) for (int j=0;j<i;j++) if (j<=size[l]&&i-j-1<=size[r]) g[x][i]=min(g[x][i],g[l][j]-f[r][i-j-1]); for (int i=0;i<=m;i++) for (int j=0;j<=i;j++) if (j<=size[l]&&i-j<=size[r]) f[x][i]=max(f[x][i],f[l][j]+f[r][i-j]); for (int i=0;i<=m;i++) for (int j=0;j<i;j++) if (j<=size[l]&&i-j-1<=size[r]) f[x][i]=max(f[x][i],f[l][j]-g[r][i-j-1]); } } int main() { scanf("%s",&s); scanf("%d%d",&p,&m); memset(f,0x8f,sizeof f); memset(g,0x3f,sizeof g); int root=build(0,strlen(s)-1); dfs(root); printf("%d",f[root][min(p,m)]); }