题意:输入一串只含 '(' , ')' 的字符串,第 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); } }