zoukankan      html  css  js  c++  java
  • P3648 [APIO2014]序列分割(斜率优化dp)

    P3648 [APIO2014]序列分割

    我们先证明,分块的顺序对结果没有影响。

    我们有一个长度为3的序列$abc$

    现在我们将$a,b,c$分开来

    随意枚举一种分块方法,如$(ab)(c)$,$(a)(b)(c)$

    答案为$(a+b)*c+a*b=ac+bc+ab$

    多枚举几种,我们发现答案总是不变的。

    所以我们可以默认每次从左到右扫,用dp求解

    对于每个$1$到$k$,我们都把序列扫一遍

    设$f[k][i]$为对前$i$个数进行$k$次切割的最大价值,

    $s[i]$为元素前缀和,那么

    $f[k][i]=f[k-1][j]+s[j]*(s[i]-s[j])$

    这个$k$显然是可以滚动优化掉的,设滚动数组为$g[i]$

    $f[i]=g[j]+s[j]*(s[i]-s[j])$

    $g[j]-s[j]^{2}=-s[i]*s[j]+f[i]$

    又化成了我们熟悉的$y=kx+b$

    $y=g[j]-s[j]^{2}$

    $k=-s[i]$

    $x=s[j]$

    $b=f[i]$

    $x,k$单调递增,于是我们直接上单调队列维护下凸包就好辣

    顺带再开个数组记录一下路径就好了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define rint register int
    using namespace std;
    typedef long long ll;
    #define N 100005
    ll s[N],f[N],g[N];
    int n,k,L,R,h[N],p[205][N];
    inline ll X(int x){return s[x];}
    inline ll Y(int x){return g[x]-s[x]*s[x];}
    inline ll KK(ll xa,ll ya,ll xb,ll yb){return ya*xb-yb*xa;}
    int main(){ 
        scanf("%d%d",&n,&k);
        for(rint i=1;i<=n;++i)
            scanf("%lld",&s[i]),s[i]+=s[i-1];
        for(rint j=1;j<=k;++j){
            h[L=R=1]=0;
            for(rint i=1;i<=n;++i){    
                while(L<R&&KK(X(h[L+1])-X(h[L]),Y(h[L+1])-Y(h[L]),1,-s[i])>=0) ++L;
                f[i]=g[h[L]]+(s[i]-s[h[L]])*s[h[L]]; p[j][i]=h[L];
                while(L<R&&KK(X(h[R])-X(i),Y(h[R])-Y(i),X(h[R])-X(h[R-1]),Y(h[R])-Y(h[R-1]))<=0) --R;
                h[++R]=i;
            }swap(g,f);
        }
        printf("%lld
    ",g[n]);//注意答案在g上
        for(rint i=k,d=p[k][n];i;--i,d=p[i][d]) printf("%d ",d);
        return 0;
    }
  • 相关阅读:
    设计模式 创建型 抽象工厂
    mysql 案例 ~ 分析执行完的大事务
    mysql 查询优化案例汇总
    mysql 原理 ~ innodb恢复机制
    mysql 原理~ 乐观锁和悲观锁
    mysql 原理 ~ 常规锁
    mysql 5.7 ~ 新特性
    mysql 原理 ~ checkpoint
    mysql原理~undo管理
    mysql原理~undo
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10751996.html
Copyright © 2011-2022 走看看