题目链接<https://cn.vjudge.net/problem/ZOJ-4027>
题意:
有一串小括号组成的字符串,每个括号都有一定的价值。如果把某一个左括号与它右边相邻的右括号交换,可以获得两者价值的乘积。问价值最高能获得多少。
题解:
对于每一个左括号,它都可以跟它后面的右括号进行交换。假设第个左括号要跟第个右括号进行交换,那么这第个右括号必须提上来,即与之间的所有左括号必须与进行过交换,而这些括号与之后的括号是否交换并不关心,对于答案来说只需要取个最大值即可。
从右往左扫,专门开一个数组存储已经扫到的右括号。每扫到一个左括号,就枚举它与每一个右括号匹配的情况。
开一个数组,存储这一次把第个括号提上来的最大价值。
开一个数组,存储上一次把第个括号提上来的最大价值。
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const ll N=1e3+7;
char s[N];
ll a[N],tp[N],maxn[N],dp[N];
int main(){
ll lo,hi,t,n;
scanf("%lld",&t);
while(t--){
memset(maxn,0,sizeof(maxn));
memset(tp,0,sizeof(tp));
ll ans=0;
scanf("%lld",&n);
scanf("%s",s+1);
for(ll i=1;i<=n;i++)
scanf("%lld",&a[i]);
hi=N-1;lo=hi+1;//lo,hi表示右括号数组的范围
for(ll i=n;i>=1;i--){
memset(dp,0,sizeof(dp));
if(s[i]==')')
tp[--lo]=a[i];
else{
ll tmp=0;
for(ll j=lo-1;j<=hi;j++){//lo-1是不跟任何一个右括号匹配的情况
tmp+=a[i]*tp[j];
dp[j]=maxn[j]+tmp;
ans=max(ans,dp[j]);
}
maxn[hi]=dp[hi];
for(ll j=hi-1;j>=0;j--)
maxn[j]=max(dp[j],maxn[j+1]);
}
}
printf("%lld\n",ans);
}
}