zoj4027 线性dp!好题
非常好的dp,可是我太菜做不出来。。
/* 第i个左括号不可能越过第i+1个左括号 如果第i个左括号到位置j,前提是第i+1个左括号就必须到位置j+1即以后 用dp[i][j]表示把第i个左括号转移到位置j的最大收益, 那么dp[i][j]=将i移到j位置的收益+max(dp[i+1][j+1..n]) 这样的复杂度是n^3,一个n的复杂度用来重复计算max(dp[i+1][j+1..n])了 那么就额外开一个数组Max[i][j]:第i个括号转移到第j个位置之后的最大收益 */ #include<bits/stdc++.h> using namespace std; #define maxn 1005 #define INF 0x3f3f3f3f long long val[maxn],dp[maxn][maxn],n,num[maxn],pos[maxn],sum[maxn],t; char s[maxn]; int main(){ cin>>t; while(t--){ cin>>n;scanf("%s",s+1); for(int i=1;i<=n;i++)cin>>val[i]; int l=0,r=0;//左括号右括号个数 for(int i=1;i<=n;i++) if(s[i]=='(') pos[++l]=i,num[l]=r; else sum[++r]=sum[r-1]+val[i]; memset(dp,0,sizeof dp); for(int i=l;i>=1;i--){//第i个左括号 for(int j=n-(l-i);j>=pos[i];j--){ long long tmp=val[pos[i]]*(sum[num[i]+j-pos[i]]-sum[num[i]]); dp[i][j]=dp[i+1][j+1]+tmp; if(j<n-(l-i))dp[i][j]=max(dp[i][j],dp[i][j+1]);//把第i个左括号移到位置j及以后的最大收益 } for(int j=pos[i]-1;j>=pos[i-1];j--)dp[i][j]=dp[i][j+1]; } long long ans=0; for(int i=1;i<=n;i++)ans=max(ans,dp[1][i]); cout<<ans<<endl; } }