题意:输入一串只含 '(' , ')' 的字符串,第 i 个字符对应vi 的分数,如果第i个字符是 '(' ,第i+1个字符是 ')' ,那么这两个字符可以互换,同时vi 和vi+1 也要互换,并且得到vi * vi+1的分数,求该字符串的最大分数。
思路:很明显 '(' 能换多少次取决于 '(' 后面有几个 ')' ,设d[ i ][ j ]为倒数第i个 '(' 换到 j 位置时取得的最大分数,那么 d[ i ][ j ]=min(d[ i ][ j ], vi*vi+1 + vi*vi+2 +....+vi*vj+max(d[ i-1 ][ j+1 ], d[ i-1 ][ j+2 ],,,,d[ i-1 ][ n ] ) )
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
char s[1005];
long long a[1005];
int t[1005];
long long d[1005][1005];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,i,j,k;
long long ans=0;
vector<int>v;
scanf("%d",&n);
scanf("%s",s+1);
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
v.push_back(0);
for(i=n;i>=1;i--)
{
if(s[i]=='(')
v.push_back(i);
}
memset(d,0,sizeof(d));
for(i=1;i<v.size();i++)
{
k=v[i]; //第i个'('的下标
int sum=0;
int tot=0;
for(j=k+1;j<=n;j++)
if(s[j]==')')
t[++tot]=j; //把i后面所有的')'下标存起来
d[i][k]=d[i-1][k+1]; //赋予初始值
for(j=k+1;j<=k+tot;j++)
{
d[i][j]=sum+a[k]*a[t[j-k]]+d[i-1][j+1]; //这个d[i][j]表示倒数第i个'('移到i之后第j个')'时的最大得分
sum+=a[k]*a[t[j-k]]; //而d[i-1][j]表示倒数第i-1个'('移动到i之后多于或等于第j个')'时的最大得分
ans=max(ans,d[i][j]);
}
int p;
for(p=k;p>=2;p--) //找到i前面一个(的的下标
if(s[p-1]=='(')
break;
for(j=k+tot-1;j>=p;j--)
d[i][j]=max(d[i][j],d[i][j+1]);//把d[i][j]更新为倒数第i个'('移到i后面大于或等于第j个')'时的最大得分
}
printf("%lld\n",ans);
}
}