#dp#NOIP2020.9.26模拟jerry
题目
Jerry 写下了一个只由非负整数和加减号组成的算式。
它想给这个算式添加合法的括号,使得算式的结果最大。
分析
考场\(O(n^3)\)伪部分分成功爆零,
设\(dp[i][j]\)表示前\(i\)个数中缺了\(j\)个右括号需要配对的最大结果,
那就考虑是加一个括号(第\(i\)个数前是负号)或不变或配对一个括号,
但是感性理解一下缺了三个或以上的右括号实际上可以被两个以内所代替
(三重否定为否定)。由于正数是可以合并的,所以括号是可以被拆开成两部分的
那么这道题就可以\(O(n)\)解决了
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011; typedef long long lll;
int n,a[N],b[N]; lll dp[N][3];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline lll max(lll a,lll b){return a>b?a:b;}
signed main(){
freopen("jerry.in","r",stdin);
freopen("jerry.out","w",stdout);
for (rr int T=iut();T;--T){
n=iut(),b[1]=0;
for (rr int i=1;i<=n;++i){
a[i]=iut();
if (i==n) continue;
rr char c=getchar();
while (c!='+'&&c!='-') c=getchar();
b[i+1]=(c=='-');
}
dp[0][0]=0,dp[0][1]=dp[0][2]=-1e18;
for (rr int i=1;i<=n;++i)
if (b[i]){
dp[i][0]=-1e18;//前面是负号强行加括号,所以不可能
dp[i][1]=max(max(dp[i-1][0],dp[i-1][1]),dp[i-1][2])-a[i];
dp[i][2]=max(dp[i-1][1],dp[i-1][2])+a[i];//变号
}else{
dp[i][0]=max(max(dp[i-1][0],dp[i-1][1]),dp[i-1][2])+a[i];
dp[i][1]=max(dp[i-1][1],dp[i-1][2])-a[i];//变号
dp[i][2]=dp[i-1][2]+a[i];//两次变号符号不变
}
printf("%lld\n",max(max(dp[n][0],dp[n][1]),dp[n][2]));
}
return 0;
}