The 15th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple / ZOJ4027 Sequence Swapping dp递推

Sequence Swapping

题意:
给出长度为 n 的一组括号,每个括号有一个权值。操作:选择一对相邻的左括号和右括号,且左括号在左,交换这两个括号,得到价值为这两个括号权值的乘积。
现在要你按这个操作,问最后的价值和最大可能是多少?
tags:
明显 dp,但很难想到。。
dp[i][j] 表示当前在第 i 个右括号,且第 i 个右括号与它前面 j 个左括号交换后的最大价值和。
我们可以预处理出第 i 个右括号与第 i-1 个右括号之间有 k 个左括号,那么转移为:

  • if(j <= k) dp[i][j] = max({dp[i-1][0], dp[i-1][1]......}) + sum(第 i 个右括号左边 j 个左括号的和) * value[i] ;
  • else dp[i][j] = max({dp[i-1][j-k], dp[i-1][j-k+1].....}) + sum(第 i 个右括号左边 j-k 个左括号的和) * value[i] ;
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 1005;

int T, n;
char s[N];
ll  val[N], cnt1[N], cnt2[N], sum[N][N], cntL, cntR;
ll  dp[N][N], vis[N], mx[N][N];
void Init() {
    cntL= cntR = 0;
    mes(cnt1, 0);  mes(cnt2, 0);
    mes(sum, 0);
    rep(i,1,N-1) rep(j,0,N-1) mx[i][j] = -1e18;
}
int main()
{
    scanf("%d", &T);
    while(T--)
    {
        Init();
        scanf("%d%s", &n, s+1);
        rep(i,1,n)
        {
            scanf("%lld", &val[i]);
            if(s[i]==')') {
                ++cntR;
                vis[i] = cntR;
                int num = 0;
                per(j,i-1,1) if(s[j]=='(') {
                    ++num;
                    sum[cntR][num] = sum[cntR][num-1]+val[j];
                }
                ll  tmp = 0;
                per(j,i-1,1) {
                    if(s[j]==')') break;
                    else  ++tmp;
                }
                cnt2[cntR] = cnt2[cntR-1]+tmp;
                cnt1[cntR] = tmp;
            }
        }

        ll  ans = 0;
        rep(i,1,n) if(s[i]==')')
        {
            int id = vis[i];
            per(j,cnt2[id],0) {
                if(j<=cnt1[id]) {
                    dp[id][j] = mx[id-1][0] + sum[id][j]*val[i];
                }
                else {
                    dp[id][j] = mx[id-1][j-cnt1[id]] + sum[id][j]*val[i];
                }
                mx[id][j] = max(mx[id][j+1], dp[id][j]);
                if(id==cntR) ans = max(ans, dp[id][j]);
            }
        }
        printf("%lld\n", ans);
    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sbfhy/p/9005028.html