原文链接http://www.cnblogs.com/zhouzhendong/p/8697258.html

题目传送门 - BZOJ3675

题意

  对于一个非负整数序列,小H需要重复k次以下的步骤:

  1.选择一个长度超过1的序列

  2.从任意位置将序列分割成两个非空的新序列。

  每次,小H将会得到分数。分数为两个新序列中元素和的乘积。请选择一种最佳的分割方式,使得k轮之后,使总得分最大。输出总得分。

  $n\leq 10^5,k\leq min(n-1,200)$

题解

  真是一道不错的题目。

  首先,我们要发掘一个性质。

对于一个最终的划分方案,以各种不同顺序划分,所得到的得分总是相同。

  设两个区间和做乘积并累加到答案里的过程为这两个区间对答案做了一次贡献。

  那么我们要证明划分完毕之后,任意两个连续区间都互相做了且仅互相做了一次贡献。

  考虑每次划分大区间的时候,划分出来的左边和右边每一个区间都做了贡献,而显然之后在左边的就不会和右边做贡献了,于是任意两个连续区间最多做一次贡献。

  考虑到对于子区间,我们不断进行子区间的左右子区间互相贡献,直到划分为1为止。

  可以感性理解一下,每一个最终区间一定会和其他所有最终区间贡献。

  或者也可以用一个更简易的证明:

  |s1|s2|s3|

  考虑以上的3段区间,区间和分别为s1,s2,s3,你可以自己试着先割s1和s2以及先割s2和s3,然后你会发现最后算出来的结果是相同的。

  所以我们可以从左到右分割。

  于是我们可以写出DP方程。

  $dp_{r,i}$表示分割了$r$次,分割到了$i$这个位置。

  设$sum_i=\sum_{j=1}^i a_j$。

  $$dp_{r,i}=max\{dp_{r-1,j}+sum_j(sum_i-sum_j)\}\ \ \ (0\leq j<i)$$

  显然可以斜率优化。

  稍微推导一下:

  $$dp_{r-1,j}+sum_j(sum_i-sum_j)\\=dp_{r-1,j}-sum_j^2+sum_jsum_i$$

  令

  $$x_i=sum_i$$

  $$y_i=dp_{r-1,i}-sum_i^2$$

  则原式=

  $$y_j+sum_ix_j$$

  假设$j>k$且从$j$转移不劣于$k$,则:

  $$y_j+sum_ix_jy_k+sum_ix_k$$

  化简得:

  $$\frac{y_j-y_k}{x_j-x_k}\geq -sum_i$$

  然后献上又一波斜率优化DP套路:

  注意由于开始限制了$j>k$所以$x_j-x_k>0$,所以最后两边同时相除不等式仍然成立。

  设

  $$g_{i,j}=\frac{y_i-y_j}{x_i-x_j}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (i>j)$$

  则上式可以表示为$g_{j,k}\geq -sum_i$

  我们来发掘以下$g_{j,k}$的性质。

  1. 当$g_{j,k}\geq -sum_i$时,由于随着$i$变大,$-sum_i$变小,所以显然从$k$转移是永远不会比$j$好的,所以我们可以把$k$扔掉。

  2. 当$g_{i,j}\geq g_{j,k}$时,从$i$或者$k$转移至少有一个不比$j$差,所以可以把$j$扔掉。为什么??

    若$g_{i,j}\geq -sum_i$,显然$j$要被扔掉,根据第一个性质。

    若$g_{i,j}<-sum_i$,则$g_{j,k}<-sum_i$,那么显然$j$比$k$差,也得被扔掉。

  于是我们可以用一个单调队列来维护斜率的单调性。

  具体的:

  当情况1发生的时候让队首出队。

  在进队的时候,如果发生情况2,那么先让队尾出队,然后再进队。

  为了避免精度问题,以及分母为0的问题,我们可以把$x_i-x_j$乘上来,用乘积式来判断大小。

  但是本题空间限制较为紧。

  所以要滚动。

  注意初始化还没有进行任何一次分割时候的$x_i,y_i$,我一开始还以为都是0,调了很久。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100005;
int n,R,q[N],head,tail;
LL sum[N],x[2][N],y[2][N],dp[2][N];
int main(){
scanf("%d%d",&n,&R);
for (int i=1;i<=n;i++)
scanf("%lld",&sum[i]),sum[i]+=sum[i-1];
int T0=1,T1=0;
for (int i=1;i<=n;i++)
x[T1][i]=sum[i],y[T1][i]=-sum[i]*sum[i];
for (int r=1;r<=R;r++){
T0^=1,T1^=1;
head=1,tail=0;
q[++tail]=0;
for (int i=1;i<=n;i++){
int j=q[head+1],k=q[head];
while (tail-head>0&&y[T0][j]-y[T0][k]>=(x[T0][j]-x[T0][k])*(-sum[i]))
head++,j=q[head+1],k=q[head];
j=k;
dp[T1][i]=dp[T0][j]+sum[j]*(sum[i]-sum[j]);
x[T1][i]=sum[i];
y[T1][i]=dp[T1][i]-sum[i]*sum[i];
j=q[tail],k=q[tail-1];
while (tail-head>0&&(y[T0][i]-y[T0][j])*(x[T0][j]-x[T0][k])>=(y[T0][j]-y[T0][k])*(x[T0][i]-x[T0][j]))
tail--,j=q[tail],k=q[tail-1];
q[++tail]=i;
}
}
printf("%lld",dp[T1][n]);
return 0;
}

  

BZOJ3675 [Apio2014]序列分割 动态规划 斜率优化的更多相关文章

  1. [Bzoj3675][Apio2014]序列分割(斜率优化)

    3675: [Apio2014]序列分割 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 4021  Solved: 1569[Submit][Stat ...

  2. BZOJ3675 [Apio2014]序列分割 【斜率优化dp】

    3675: [Apio2014]序列分割 Time Limit: 40 Sec  Memory Limit: 128 MB Submit: 3366  Solved: 1355 [Submit][St ...

  3. 2018.09.29 bzoj3675: [Apio2014]序列分割(斜率优化dp)

    传送门 斜率优化dp经典题目. 首先需要证明只要选择的K个断点是相同的,那么得到的答案也是相同的. 根据分治的思想,我们只需要证明有两个断点时成立,就能推出K个断点时成立. 我们设两个断点分成的三段连 ...

  4. BZOJ3675 Apio2014 序列分割 【斜率优化】

    Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序列,小H需要重复k次以下的步骤: 1.小H首 ...

  5. BZOJ 3675: [Apio2014]序列分割 动态规划 + 斜率优化 + 卡精度

    Code: #include<bits/stdc++.h> #define N 100006 #define M 205 #define ll long long #define setI ...

  6. 【BZOJ3675】序列分割(斜率优化,动态规划)

    [BZOJ3675]序列分割(斜率优化,动态规划) 题面 Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得 ...

  7. BZOJ_3675_[Apio2014]序列分割_斜率优化

    BZOJ_3675_[Apio2014]序列分割_斜率优化 Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了 ...

  8. 【BZOJ-3675】序列分割 DP + 斜率优化

    3675: [Apio2014]序列分割 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 1420  Solved: 583[Submit][Statu ...

  9. BZOJ 3675: [Apio2014]序列分割( dp + 斜率优化 )

    WA了一版... 切点确定的话, 顺序是不会影响结果的..所以可以dp dp(i, k) = max(dp(j, k-1) + (sumn - sumi) * (sumi - sumj)) 然后斜率优 ...

随机推荐

  1. 转载:Eureka 开发时快速剔除失效服务

    原文地址:https://www.cnblogs.com/flying607/p/8494568.html 服务端配置: # 关闭保护机制 eureka.server.enable-self-pres ...

  2. 异步io模块

    '''客户端''' import socket,select #####进行封装,将socket对象和要返回的url,和回调函数进行一下封装 class Httprequest(): def __in ...

  3. JS访问SpringMVC后台

    var actions=ctx.path + "/api/stat/exportScheStatInfo.json"; var form = $("<form> ...

  4. 部署apache-tomcat环境

    软件体系: C/S:客户端/服务器,例如qq等app都属于C/S体系,除了编写服务端代码还需要编写客户端 优点:展现比较好,客户端会承受一点运算压力,安全性比较好 缺点:更新服务端的同时还需要更新客户 ...

  5. Jquyer轮播带数字和提示文字

    效果图如下: 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http: ...

  6. Python-计算机硬件基础

    预习计算机硬件基础1,CPU/内存.硬盘2,存储器 什么是编程语言什么是编程编程的目的运行程序的三大核心硬件重要:运行程序,硬件的工作过程 ------------------------------ ...

  7. input错误提示,点击提交,提示有未填项,屏幕滑到input未填项的位置

    function errorInfo(parm) { //获取文本框值 var $val = parm.val(); if ($val==""||undefined||null){ ...

  8. PID控制器开发笔记之十:步进式PID控制器的实现

    对于一般的PID控制系统来说,当设定值发生较大的突变时,很容易产生超调而使系统不稳定.为了解决这种阶跃变化造成的不利影响,人们发明了步进式PID控制算法. 1.步进式PID的基本思想 所谓步进式PID ...

  9. 对一个元素 同时添加单击onclick 和 双击ondblclick 触发冲突的解决

    需求说明:单击列表项内容后,吧啦吧啦,双击列表项内容后,巴拉巴拉巴拉~~~ 解决思路:卧槽 ,其实我是没思路的,当时唯一的想法就是,看个人点击鼠标的速度了,双击快一点,触发双击事件ლ(′◉❥◉`ლ), ...

  10. php 统计某个目录中所有文件的大小

    /** * @Purpose : 利用递归的方式统计目录的大小 * @Author : chrdai * @Method Name : dirSize() * @parameter : string ...