题目大意
给出一个表达式,符号位置全部用?
替代,
已知运算只有加法和减法,并且知道有
p
p
p次加法和
m
m
m次加法。
问这个表达式的最大值是多少。
时间限制
2s
数据范围
m
i
n
p
.
m
≤
100
min{p.m}\le 100
minp.m≤100
表达式长度
≤
1
0
4
\le 10^4
≤104
题解
这题细节比较多,特别是处理这个字符串表达式的时候。
先将表达式处理成为树,然后就可以在树上dp了。
设
f
i
,
j
f_{i,j}
fi,j表示在第
i
i
i个结点,使用了
j
j
j次运算(次数较少的那一种运算)的最大值。
设
g
i
,
j
g_{i,j}
gi,j表示在第
i
i
i个结点,使用了
j
j
j次运算(次数较少的那一种运算)的最小值。
转移就是枚举左子树使用多少次运算即可。
Code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#define G getchar
#define ll long long
using namespace std;
ll read()
{
char ch;
for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());
ll n = 0 , w;
if (ch == '-')
{
w = -1;
ch = G();
} else w = 1;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n * w;
}
const int N = 20004;
int nxt[N] , ls[N] , rs[N] , tot;
int f[N][103] , g[N][103] , p , m , n , op;
int z[N] , top , ans , si[N];
char s[N];
void build (int x , int l , int r)
{
if (l == r)
{
g[x][0] = f[x][0] = s[l] - 48;
return;
}
int p;
if (s[l] == '(')
{
if (r == nxt[l])
{
build(x , l + 1 , r - 1);
return;
}
tot++;
ls[x] = tot;
build(ls[x] , l + 1 , nxt[l] - 1);
tot++;
rs[x] = tot;
build(rs[x] , nxt[l] + 2 , r);
}
else
{
tot++;
ls[x] = tot;
build(ls[x] , l , l);
tot++;
rs[x] = tot;
build(rs[x] , l + 2 , r);
}
}
void dfs1(int x)
{
if (f[x][0] > 0) return;
dfs1(ls[x]);
dfs1(rs[x]);
si[x] = si[ls[x]] + si[rs[x]] + 1;
for (int i = 1 ; i <= min(si[x] , n) ; i++)
{
for (int j = 0 ; j < i ; j++)
{
if (f[ls[x]][j] > - 10 * N && g[rs[x]][i - j] < 10 * N)
f[x][i] = max(f[x][i] , f[ls[x]][j] - g[rs[x]][i - j]);
if (f[ls[x]][j] > - 10 * N && f[rs[x]][i - j - 1] > - 10 * N)
f[x][i] = max(f[x][i] , f[ls[x]][j] + f[rs[x]][i - j - 1]);
if (g[ls[x]][j] < 10 * N && f[rs[x]][i - j] > - 10 * N)
g[x][i] = min(g[x][i] , g[ls[x]][j] - f[rs[x]][i - j]);
if (g[ls[x]][j] < 10 * N && g[rs[x]][i - j - 1] < 10 * N)
g[x][i] = min(g[x][i] , g[ls[x]][j] + g[rs[x]][i - j - 1]);
}
if (f[ls[x]][i] > - 10 * N) f[x][i] = max(f[x][i] , f[ls[x]][i] - g[rs[x]][0]);
if (g[ls[x]][i] < 10 * N) g[x][i] = min(g[x][i] , g[ls[x]][i] - f[rs[x]][0]);
}
f[x][0] = f[ls[x]][0] - f[rs[x]][0];
g[x][0] = g[ls[x]][0] - g[rs[x]][0];
}
void dfs2(int x)
{
if (f[x][0] > 0) return;
dfs2(ls[x]);
dfs2(rs[x]);
si[x] = si[ls[x]] + si[rs[x]] + 1;
for (int i = 1 ; i <= min(si[x] , n) ; i++)
{
for (int j = 0 ; j < i ; j++)
{
if (f[ls[x]][j] > - 10 * N && f[rs[x]][i - j] > - 10 * N)
f[x][i] = max(f[x][i] , f[ls[x]][j] + f[rs[x]][i - j]);
if (f[ls[x]][j] > - 10 * N && g[rs[x]][i - j - 1] < 10 * N)
f[x][i] = max(f[x][i] , f[ls[x]][j] - g[rs[x]][i - j - 1]);
if (g[ls[x]][j] < 10 * N && g[rs[x]][i - j] < 10 * N)
g[x][i] = min(g[x][i] , g[ls[x]][j] + g[rs[x]][i - j]);
if (g[ls[x]][j] < 10 * N && f[rs[x]][i - j - 1] > - 10 * N)
g[x][i] = min(g[x][i] , g[ls[x]][j] - f[rs[x]][i - j - 1]);
}
if (f[ls[x]][i] > - 10 * N) f[x][i] = max(f[x][i] , f[ls[x]][i] + f[rs[x]][0]);
if (g[ls[x]][i] < 10 * N) g[x][i] = min(g[x][i] , g[ls[x]][i] + g[rs[x]][0]);
}
f[x][0] = f[ls[x]][0] + f[rs[x]][0];
g[x][0] = g[ls[x]][0] + g[rs[x]][0];
}
int main()
{
//freopen("h.in","r",stdin);
//freopen("2.txt","w",stdout);
scanf("%s", s + 1);
p = read();
m = read();
s[0] = '#';
n = strlen(s) - 1;
top = 0;
for (int i = 1 ; i <= n ; i++)
{
if (s[i] == '(')
{
top++;
z[top] = i;
}
if (s[i] == ')')
{
nxt[z[top]] = i;
top--;
}
}
tot = 1;
memset(f , 128 , sizeof(f));
memset(g , 127 , sizeof(g));
build(1 , 1 , n);
if (p < m)
{
n = p;
dfs1(1);
}
else
{
n = m;
dfs2(1);
}
printf("%d\n", f[1][n]);
return 0;
}