ZOJ Problem Set - 4027 Sequence Swapping (DP)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5768

题面:

BaoBao has just found a strange sequence {<, >, <, >, , <, >} of length in his pocket. As you can see, each element <, > in the sequence is an ordered pair, where the first element in the pair is the left parenthesis '(' or the right parenthesis ')', and the second element in the pair is an integer.

As BaoBao is bored, he decides to play with the sequence. At the beginning, BaoBao's score is set to 0. Each time BaoBao can select an integer , swap the -th element and the -th element in the sequence, and increase his score by , if and only if , '(' and ')'.

BaoBao is allowed to perform the swapping any number of times (including zero times). What's the maximum possible score BaoBao can get?

Input

There are multiple test cases. The first line of the input contains an integer , indicating the number of test cases. For each test case:

The first line contains an integer (), indicating the length of the sequence.

The second line contains a string () consisting of '(' and ')'. The -th character in the string indicates , of which the meaning is described above.

The third line contains integers (). Their meanings are described above.

It's guaranteed that the sum of of all test cases will not exceed .

Output

For each test case output one line containing one integer, indicating the maximum possible score BaoBao can get.

Sample Input

4
6
)())()
1 3 5 -1 3 2
6
)())()
1 3 5 -100 3 2
3
())
1 -1 -1
3
())
-1 -1 -1

Sample Output

24
21
0
2

Hint

For the first sample test case, the optimal strategy is to select in order.

For the second sample test case, the optimal strategy is to select in order.

题意:给一只含括号符号的串,每个符号一个权值v[i],相邻的'('和')'可以交换[左括号在前],贡献为两个符号的权值积,即第i位和第i+1位若符合交换条件,则交换之后答案值加上v[i]*v[j],求最大的答案值

思路:把左括号和右括号分别存在两个数组里,然后以右括号位置从左到右进行dp(或者左括号位置从后往前dp),dp[i][j]表示第i个右括号挪到第j个位置或该位置左边时最大的答案值,则第i+1个括号最多能左移的次数就是其位置和j位置之间的左括号数,可以得到状态转移方程

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 1005;
#define INF 0xffffff

ll dp[maxn][maxn];
int t, n;
ll v[maxn], sum[maxn];//sum数组记录左括号的权值前缀和,序号为左括号个数
char s[maxn];
int p[maxn], cnt, m[maxn], mc;//p数组记录右括号位置,m数组记录左括号位置

void init()
{
    memset(p,0,sizeof(p));
    memset(m,0,sizeof(m));
    mc = 1;
    cnt = 1;
    sum[0] = 0;
}

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        init();
        scanf("%d",&n);
        scanf("%s",s);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&v[i]);
            if(s[i-1]==')')
            {
                p[cnt++] = i;
            }
            else
            {
                m[mc] = i;
                sum[mc]=sum[mc-1]+v[i];
                mc++;
            }
        }
        for(int i=0;i<cnt;i++)
        {
            for(int j = 0;j<p[i];j++)
                dp[i][j] = -INF;
            dp[i][p[i]] = 0;
        }
        ll ans = 0;
        int le = 1;
        for(int i=1;i<cnt;i++)
        {
            int now = p[i];
            for(int j = 0;j<=now-le;j++)//j是当前右括号最多能向左交换的次数
            {
                dp[i][now-j] = max(dp[i][now-j],v[now]*(sum[now-i]-sum[now-i-j])+dp[i-1][min(now-j-1,p[i-1])]);//维护dp[i][j]为第i个右括号在j位置的答案值
                ans = max(ans,dp[i][now-j]);
            }
            for(int j = le+1;j<=now;j++)
            {
                dp[i][j] = max(dp[i][j-1],dp[i][j]);//维护dp[i][j]为第i个右括号在j位置或左边的答案值
                ans = max(ans,dp[i][j]);
            }
            le++;
        }
        printf("%lld\n",ans);
   }
}

猜你喜欢

转载自blog.csdn.net/AmarisCR/article/details/86506296