D:Sequence Swapping ZOJ 4027 dp

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4027

dp题,比赛的时候的知道是dp,但是就是想不出来,回来虽然想出来了,但是调了2个多小时才调出来。

好像同队的大佬也有用线段树写的,0rz。

注意理解下,每个左括号都可以换到他右边的所有右括号,但是前提是这个右括号要先和他们之间的所有左括号先换一下,这个左括号要和他们之间所有的右括号也换一下。

然后我对于每个右括号 j 设一个dp[ j ], 用来存这里的能换到的最大值。

思路就是从左往右对于每个左括号 i 往右遍历,遇见左括号就加上(计算前缀和,这里叫做tem_sum),然后遇见右括号 j 就把前缀和和他的值乘一下,然后这样还不够因为还要考虑左括号们移过来和前面的右括号产生的值(这里叫做tem_val),然后用 tem_sum*val[ j ] + tem_val 尝试更新一下dp[ j ]。

然后考虑下tem_val的获取,对于每个左括号i,他的起始tem_val应该是他左边区间dp所能拿到的最大值,当然也可以不拿,就取0。然后对于他右边的右括号 j 每次更新一个 dp[j] 之后,tem_val更新成这个 dp[ j ] 就可以了,因为 dp[ j ] 已经是 i 和 i 左边所有其他左括号移到这里的情况下可以拿到的最大值了。

 

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 1e3 + 5;
int figure[MAXN], val[MAXN];
long long dp[MAXN];
int main(){
    int t, n;
    int i, j;
    long long tem_sum, tem_val;
    char tc;
    scanf("%d", &t);
    while(t--){
        memset(dp, 0, sizeof(dp));
        scanf("%d", &n);
        for (i = 1; i <= n; i++)
        {
            scanf("%c", &tc);
            switch(tc){
                case '(':
                    figure[i] = 0;
                    break;
                case ')' :
                    figure[i] = 1;
                    break;
                default:
                    i--;
            }
        }
        for (i = 1; i <= n; i++){
            scanf("%d", &val[i]);
        }
        for (i = 1; i <= n; i++){
            if(figure[i]){
                dp[i] = max(dp[i], dp[i - 1]);
            }
            else{
                tem_sum = val[i];
                tem_val = dp[i - 1]<0?0:dp[i - 1];
                dp[i] = tem_val;
                for (j = i + 1; j <= n; j++)
                {
                    if(figure[j]){
                        if(figure[j] == 1){
				figure[j] = 2;
                        	dp[j] = tem_sum * val[j] + tem_val;
                        }
                        else{
                        	
                        	dp[j] = max(dp[j], tem_sum * val[j] + tem_val);
                        }
                        tem_val = dp[j];
                    }
                    else{
                        tem_sum += val[j];
                    }
                }
            }
        }
        printf("%lld\n", dp[n]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值