BZOJ3675 [Apio2014]序列分割 动态规划 斜率优化
原文链接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]序列分割 动态规划 斜率优化的更多相关文章
- [Bzoj3675][Apio2014]序列分割(斜率优化)
3675: [Apio2014]序列分割 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 4021 Solved: 1569[Submit][Stat ...
- BZOJ3675 [Apio2014]序列分割 【斜率优化dp】
3675: [Apio2014]序列分割 Time Limit: 40 Sec Memory Limit: 128 MB Submit: 3366 Solved: 1355 [Submit][St ...
- 2018.09.29 bzoj3675: [Apio2014]序列分割(斜率优化dp)
传送门 斜率优化dp经典题目. 首先需要证明只要选择的K个断点是相同的,那么得到的答案也是相同的. 根据分治的思想,我们只需要证明有两个断点时成立,就能推出K个断点时成立. 我们设两个断点分成的三段连 ...
- BZOJ3675 Apio2014 序列分割 【斜率优化】
Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序列,小H需要重复k次以下的步骤: 1.小H首 ...
- BZOJ 3675: [Apio2014]序列分割 动态规划 + 斜率优化 + 卡精度
Code: #include<bits/stdc++.h> #define N 100006 #define M 205 #define ll long long #define setI ...
- 【BZOJ3675】序列分割(斜率优化,动态规划)
[BZOJ3675]序列分割(斜率优化,动态规划) 题面 Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得 ...
- BZOJ_3675_[Apio2014]序列分割_斜率优化
BZOJ_3675_[Apio2014]序列分割_斜率优化 Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了 ...
- 【BZOJ-3675】序列分割 DP + 斜率优化
3675: [Apio2014]序列分割 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1420 Solved: 583[Submit][Statu ...
- BZOJ 3675: [Apio2014]序列分割( dp + 斜率优化 )
WA了一版... 切点确定的话, 顺序是不会影响结果的..所以可以dp dp(i, k) = max(dp(j, k-1) + (sumn - sumi) * (sumi - sumj)) 然后斜率优 ...
随机推荐
- Linux IO模型和网络编程模型
术语概念描述: IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者. 阻塞和非阻塞,是函数/方法的实现方式,即在数据就绪之前是立刻返回还是等待. 以文件IO为例,一个IO读过程是文件 ...
- tomcat8编码
web工程,本机能跑的代码放到生产环境中后能跑但是得不到预期的结果,十有八九的原因是 编码问题
- ldconfig deferred processing now taking place
在ubuntu下面安装软件,安装结束后,提示:ldconfig deferred processing now taking place 到网上查询了一下,大概意思是说:软件安装完了,是否要重启电脑.
- Eclipse设置选中高亮显示(包含debug)
如果不高亮显示了:工具栏里有个黄色小笔的图标,点一下就可以了,或者alt+shift+O 设置高亮显示:
- 【转】VSync Count 垂直同步
原文:http://blog.csdn.net/yesy10/article/details/7794556 Unity3D中新建一个场景空的时候,帧速率(FPS总是很低),大概在60~70之间.一直 ...
- 2015第24周二Spring事务2
今天继续深入学习SPring事务,发现网上很多文章都是很相似的转载没多少价值,就觉得更有必要把这个主题深入下去,先是摘录那些对自己有用的观点,后期再结合源码进行全面的整理. Spring提供了许多内置 ...
- Python装饰器学习
Python装饰器学习(九步入门) 这是在Python学习小组上介绍的内容,现学现卖.多练习是好的学习方式. 第一步:最简单的函数,准备附加额外功能 ? 1 2 3 4 5 6 7 8 # -*- ...
- epoll ET(边缘触发) LT(水平触发)
EPOLL事件有两种模型: Edge Triggered (ET) 边缘触发只有数据到来,才触发,不管缓存区中是否还有数据.Level Triggered (LT) 水平触发只要有数据都会触发. 首先 ...
- Selling Souvenirs CodeForces - 808E (分类排序后DP+贪心)
E. Selling Souvenirs time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- Mysql中 in or exists not exists not in区别 (网络整理)
in 和or区别: 如果in和or所在列有索引或者主键的话,or和in没啥差别,执行计划和执行时间都几乎一样. 如果in和or所在列没有 索引的话,性能差别就很大了.在没有索引的情况下,随着in或者o ...