YbtOJ NOIP模拟 序列收益


题目

开始有 n n n个物品按从左到右的顺序排成一行,第 i i i个物品有一个代价 a i a_i ai和一个价值 b i b_i bi。每次操作,你可以选择两个相邻的,并且代价之和不超过 K K K的物品,将它们从序列中删去,并获得两个物品价值之和的收益。每次删去这两个物品后,就认为这两个物品的左边和右边的就变成相邻的了。求最大化价值。
n ≤ 800 n\le 800 n800

比赛没打,赛后看了看题,十分一眼,看正解好像也是这样搞的


早上状态就是香,一眼区间dp, f l , r f_{l,r} fl,r表示消除 l l l r r r 的最大价值,按照以往的思路,显然 f l , r = m a x l ≤ k < r ( f l , k + f k + 1 , r ) f_{l,r}=max_{l\le k<r}(f_{l,k}+f_{k+1,r}) fl,r=maxlk<r(fl,k+fk+1,r)

但是这种情况是不包括中间全消去,两边变成相邻消去的情况的。那我就把这种情况的最简状态考虑一下,也就是当中间消去, l l l r r r 成为相邻且消去时

f l + 1 , r − 1 = s u m l + 1 , r − 1 a l + a r ≤ K f_{l+1,r-1}=sum_{l+1,r-1}\\a_l+a_r\le K fl+1,r1=suml+1,r1al+arK

对于这种情况而言, f l + 1 , r − 1 = s u m l , r f_{l+1,r-1}=sum_{l,r} fl+1,r1=suml,r 一定最优

综上所述,

f l , r = { s u m l , r f l + 1 , r − 1 = s u m l + 1 , r − 1 且 a l + a r ≤ K m a x l ≤ k < r ( f l , k + f k + 1 , r ) e l s e f_{l,r}=\left\{ \begin{array}{rcl} sum_{l,r} && {f_{l+1,r-1}=sum_{l+1,r-1}且a_l+a_r\le K}\\ max_{l\le k<r}(f_{l,k}+f_{k+1,r}) && {else}\\ \end{array} \right. fl,r={suml,rmaxlk<r(fl,k+fk+1,r)fl+1,r1=suml+1,r1al+arKelse
code

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=810;
int n,K,a[maxn],b[maxn],f[maxn][maxn],s[maxn];
signed main()
{
    cin>>n>>K;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i]>>b[i];
        if(i>1&&a[i]+a[i-1]<=K) f[i-1][i]=b[i-1]+b[i];
        s[i]=s[i-1]+b[i];
    }
    for(int len=3;len<=n;len++)
        for(int l=1;l+len-1<=n;l++)
        {
            int r=l+len-1;
            if(f[l+1][r-1]==s[r-1]-s[l]&&a[l]+a[r]<=K) f[l][r]=s[r]-s[l-1];
            else for(int k=l;k<r;k++)
                f[l][r]=max(f[l][r],f[l][k]+f[k+1][r]);
        }
    cout<<f[1][n]<<endl;
    return 0;
}

一点小收获

  • 对于区间dp而言,要对于某种情况的最简状态抽象出来,而不要去想复杂的包含很多特定情况下的复杂状态。

  • 考虑合并正确性的时候,不要孤立地去仅限于特定的两个子区间去想

    比如这道题,刚思考合并的时候,会陷入一个误区,也就是当两个子区间均有剩余时,剩余还能合并,抽象成最简状态就是(U1与U2能合并,但是其均不能与其所在区间合并)
    然后竟然想对每个状态开个vector,但好在马上我就否定了这种情况

    因为事实上会取到另两个子区间
    请添加图片描述
    然后对于子区间,直接最优的合并。请添加图片描述

很难想象如果当我不清醒的时候,陷入了误区的后果

所以要真正明白一个算法的精髓。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值