1. 程式人生 > >【DP】ZOJ - 4027 - Sequence Swapping

【DP】ZOJ - 4027 - Sequence Swapping

題目連結<https://cn.vjudge.net/problem/ZOJ-4027>


題意:

 有一串小括號組成的字串,每個括號都有一定的價值。如果把某一個左括號與它右邊相鄰的右括號交換,可以獲得兩者價值的乘積。問價值最高能獲得多少。


題解:

對於每一個左括號,它都可以跟它後面的右括號進行交換。假設第i個左括號要跟第j個右括號進行交換,那麼這第j個右括號必須提上來,即ij之間的所有左括號必須與j進行過交換,而這些括號與j之後的括號是否交換並不關心,對於答案來說只需要取個最大值即可。

從右往左掃,專門開一個數組儲存已經掃到的右括號。每掃到一個左括號,就列舉它與每一個右括號匹配的情況。

開一個dp[j]陣列,儲存這一次把第j個括號提上來的最大價值。

開一個maxn[j]陣列,儲存上一次把第j個括號提上來的最大價值。


#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);
    }
}