P6563 [SBCOI2020] 一直在你身旁 题解

dp 好题,论观察性质的重要性

Statement

[P6563 SBCOI2020] 一直在你身旁 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Solution

我们容易得到一个 \(O(Tn^3)\) 的暴力 \(dp\) ,设 \(dp_{l,r}\) 表示知道答案在 \([l,r]\)还需要的最少代价,那么

\[dp_{l,r}=\min_k\{\max\{dp_{l,k},dp_{k+1,r}\}+a_k\} \]

我们感觉 \(\max\) 很烦,观察到随着 \(k\) 的增大,\(dp_{l,k}\) 递增, \(dp_{k+1,r}\) 递减,所以我们能够找到一个分界点 \(p\) 使得 \(dp_{l,p+1}> dp_{p,r},dp_{l,p}\le dp_{p-1,r}\) ,我们记这个分界点叫做 \(g(l,r)\)

所以我们现在有了拆开这个 \(\max\) 的权利,我们可以考虑每次 \(\log\) 二分出这个分界点 \(g(l,r)\)

又观察到 \(g(l,r)<g(l,r+1)\) ,因为 \(dp_{k,r+1}>dp_{k,r}\) ,即 \(g(l,r)\) 是单调的,于是我们干掉了那个 \(\log\)

现在我们分开考虑:

  • 对于 \(dp_{k+1,r}\ge dp_{l,k}\) ,即 \(k<g(l,r)\) ,转移变成 \(dp_{l,r}=\min\{dp_{k+1,r}+a_k\}\),我们直接上一个单调队列即可(防止决策点跑到 \(\ge g(l,r)\) 的位置去了)
  • 对于 \(dp_{k+1,r}<dp_{i,k}\) ,即 \(k\ge g(l,r)\) ,转移变成 \(dp_{l,r}=\min\{dp_{l,k}+a_k\}\) ,注意到 \(a_i\) 是递增的,\(dp_{l,i}\) 也是递增的,所以这里我们直接取 \(k=g(l,r)\)\(dp_{l,r}=dp_{l,g(l,r)}+a_{g(l,r)}\) 就好

所以复杂度 \(O(Tn^2)\)

Code

久了没写单调队列,一堆锅(

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 7105;

char buf[1<<23],*p1=buf,*p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
int read(){
    int s=0,w=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
    return s*w;
}

int a[N],q[N],dp[N][N];
int T,n;

signed main(){
    T=read();
    while(T--){
        n=read();
        for(int i=1;i<=n;++i)a[i]=read();
        for(int r=2;r<=n;++r){
            int hd=1,tl=2; q[1]=r;
            for(int l=r,p=r;l>=1;--l){
                if(l==r){dp[l][r]=0;continue;}//
                if(l+1==r){dp[l][r]=a[l];continue;}//
                while(p>l&&dp[l][p-1]>dp[p][r])--p;
                dp[l][r]=dp[l][p]+a[p];
                while(hd<tl&&q[hd]>=p)hd++;//
                if(hd<tl)dp[l][r]=min(dp[l][r],dp[q[hd]+1][r]+a[q[hd]]);
                while(hd<tl&&dp[l+1][r]+a[l]<=dp[q[tl-1]+1][r]+a[q[tl-1]])--tl;
                q[tl++]=l;//
            }
        }
        printf("%lld\n",dp[1][n]);
    }
    return 0;
}

想要一直在你身旁呀

posted @ 2022-02-12 15:53  _Famiglistimo  阅读(33)  评论(0编辑  收藏  举报