zoukankan      html  css  js  c++  java
  • BZOJ 3675 [Apio2014]序列分割 (斜率优化DP)

    洛谷传送门

    题目大意:让你把序列切割k次,每次切割你能获得 这一整块两侧数字和的乘积 的分数,求最大的分数并输出切割方案

    神题= =

    搞了半天也没有想到切割顺序竟然和答案无关...我太弱了

    证明很简单,就是乘法分配律,把式子展开就行了

    定义$s_{i}$为序列$a$的前缀和,定义$f[k][i]$表示第$k$次切割是在第$i$个位置的后面,$f[k][i]=max(f[k-1][j]+(s_{i}-s_{j})*(s_{n}-s_{i}))$

    展开式子,移项,发现$x$递增,斜率$k$也递增,用队列维护上凸包就行了

    至于记录方案,另开一个数组,记录从哪转移来的就行了

    复杂度$O(nk)$

    又没长记性把$i$打成$j$了(捂脸)

     1 #include <cmath>
     2 #include <queue>
     3 #include <vector>
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <algorithm>
     7 #define N1 101000
     8 #define M1 205
     9 #define ll long long
    10 #define dd double  
    11 #define uint unsigned int
    12 #define idx(X) (X-'0')
    13 using namespace std;
    14 
    15 int gint()
    16 {
    17     ll ret=0;int fh=1;char c=getchar();
    18     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    19     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
    20     return ret*fh;
    21 }
    22 int n,K;
    23 int a[N1];
    24 ll sa[N1],f[2][N1],x[N1],y[N1];
    25 int fa[M1][N1];
    26 int que[N1],ret[N1];
    27 
    28 int main()
    29 {
    30     freopen("t2.in","r",stdin);
    31     scanf("%d%d",&n,&K);
    32     for(int i=1;i<=n;i++)
    33         a[i]=gint(),sa[i]=sa[i-1]+a[i];
    34     int now=1,pst=0;
    35     for(int k=1;k<=K;k++)
    36     {
    37         int hd=1,tl=0,j;
    38         que[++tl]=0;
    39         for(int i=1;i<n;i++)
    40         {
    41             while(hd+1<=tl&&(y[que[hd+1]]-y[que[hd]])>=-(x[que[hd+1]]-x[que[hd]])*sa[i])
    42                 hd++;
    43             j=que[hd];
    44             f[now][i]=f[pst][j]+(sa[i]-sa[j])*(sa[n]-sa[i]);
    45             fa[k][i]=j;
    46             x[i]=sa[i],y[i]=f[pst][i]-sa[i]*sa[n];
    47             while(hd+1<=tl&&(y[i]-y[que[tl-1]])*(x[que[tl]]-x[que[tl-1]])>=(y[que[tl]]-y[que[tl-1]])*(x[i]-x[que[tl-1]]))
    48                 tl--;
    49             que[++tl]=i;
    50         }swap(now,pst);
    51     }
    52     ll ans=0,id=0;
    53     for(int i=1;i<n;i++)
    54         if(f[pst][i]>ans)
    55         ans=f[pst][i],id=i;
    56     for(int k=K;k>=1;k--)
    57         ret[k]=id,id=fa[k][id];
    58     printf("%lld
    ",ans);
    59     for(int k=1;k<=K;k++)
    60         printf("%d ",ret[k]);
    61     puts("");
    62     return 0;
    63 }
  • 相关阅读:
    Codeforces Round #595 (Div. 3) A,B,C,D
    计算几何板子题【2019牛客国庆集训派对day7——三角形和矩形】【多边形相交的面积】
    [POJ]POJ1753(dfs)
    [POJ]POJ2965(dfs)
    洛谷 P1772 [ZJOI2006]物流运输 题解
    简单概率与期望
    洛谷 P3802 小魔女帕琪 题解
    用树状数组实现的平衡树
    【模板】扩展中国剩余定理(EXCRT)
    新博客开通通知
  • 原文地址:https://www.cnblogs.com/guapisolo/p/10050677.html
Copyright © 2011-2022 走看看