Codeforces935E Fafa and Ancient Mathematics
题意:一个类似(a?(b?c))的序列(l<1e4),?代表+或者-,告诉序列中+的数量和-的数量min(+, -)<=100,问这个表达式的最大值是多少
题解:这个序列可以看成一颗树,叶子节点就是值,其他节点代表运算符,限制了+,-的数量,树形dp,dp1[i][j]代表i这个节点有j个数量少的符号(包括自己)的最大值,dp2代表最小值
当前节点为x,儿子节点包括本身有i个符号, 枚举左边的符号个数j,那么右边就是i-j或者是i-j-1
max = max-min;min = min-max;
max = max+max;min = min+min;
这里建树nlgn
#include <bits/stdc++.h> #define maxn 10010 #define INF 0x3f3f3f3f using namespace std; struct node{ int l, r, d, c; node(){l = r = d = -1;c = 0;} }a[maxn]; int cnt = 0, dp1[maxn][110], dp2[maxn][110], flag, p, m; char s[maxn]; int dfs(int ll,int rr){ if(ll == rr){ a[++cnt].d = s[ll]-'0'; a[cnt].c = 0; dp1[cnt][0] = dp2[cnt][0] = a[cnt].d; return cnt; } int num = 0, mid; for(int i=ll;i<=rr;i++){ if(s[i] == '(') num++; if(s[i] == ')') num--; if(num == 1&&s[i] == '?'){ mid = i; break; } } int t = ++cnt; a[t].d = 10; a[t].l = dfs(ll+1, mid-1); a[t].r = dfs(mid+1, rr-1); a[t].c = a[a[t].l].c+a[a[t].r].c+1; int x = t, l = a[x].l, r = a[x].r; if(flag){ for(int i=0;i<=a[x].c;i++) for(int j=0;j<=a[l].c&&j<=i;j++) if(i-j<=a[r].c){ dp1[x][i] = max(dp1[x][i], dp1[l][j]-dp2[r][i-j]); dp2[x][i] = min(dp2[x][i], dp2[l][j]-dp1[r][i-j]); if(i<=a[x].c-1){ dp1[x][i+1] = max(dp1[x][i+1], dp1[l][j]+dp1[r][i-j]); dp2[x][i+1] = min(dp2[x][i+1], dp2[l][j]+dp2[r][i-j]); } } } else{ for(int i=0;i<=a[x].c;i++) for(int j=0;j<=a[l].c&&j<=i;j++) if(i-j<=a[r].c){ dp1[x][i] = max(dp1[x][i], dp1[l][j]+dp1[r][i-j]); dp2[x][i] = min(dp2[x][i], dp2[l][j]+dp2[r][i-j]); if(i<=a[x].c-1){ dp1[x][i+1] = max(dp1[x][i+1], dp1[l][j]-dp2[r][i-j]); dp2[x][i+1] = min(dp2[x][i+1], dp2[l][j]-dp1[r][i-j]); } } } return t; } int main(){ scanf("%s", s); scanf("%d%d", &p, &m); int len = strlen(s); memset(dp2, INF, sizeof(dp2)); memset(dp1, -INF, sizeof(dp1)); flag = p<m?1:0; dfs(0, len-1); cout<<dp1[1][min(p, m)]<<endl; return 0; }
posted on 2018-03-18 21:23 2855669158 阅读(179) 评论(0) 编辑 收藏 举报