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)) 然后斜率优 ...
随机推荐
- eclipse的工程中如何查找字符串
ctrl + h 后弹出 tab选项, 你选择 file search 然后在下面输入要查找的字符串 workset 那里选择你要查找的项目 默认是全部项目进行查找
- JMeter实现唯一参数生成不重复时间戳
现象: 使用jmeter做接口压测时,总会遇到压测时,提示不允许重复id或提示订单不允许重复现象,那么如何解决呢? 原料工具 jmeter4.0 本地准备好接口服务 思路: 单个接口,小批量接口,一般 ...
- Day7--------------IP地址与子网划分
1.ip地址:32位 172.16.45.10/16 网络位:前十六位是网络位 主机位:后16位是主机位 网络地址:172.16.0.0 主机地址:172.16.45.10 A类: 0NNNNN ...
- JavaScript 删除某个数组中指定的对象
返回对象在数组中的下标: _arr表示一个Array数组,里面包括了很多的对象如下图: _obj表示某一个数组对象 function getIndex (_arr,_obj) { var le ...
- Navicat系列产品激活教程
准备 本教程可破解12.x版本,如果教程失效请联系我 # 19.1.11 破解暂时失效,请勿更新 (如已更新请卸载重新安装老版本,数据不会丢失 http://download.navicat.com/ ...
- 初学python之路-day14
一.带参装饰器 # 通常,装饰器为被装饰的函数添加新功能,需要外界的参数 # -- outer参数固定一个,就是func # -- inner参数固定同被装饰的函数,也不能添加新参数 # -- 可以借 ...
- bat脚本(转)
偶尔用到,搜到不错的资料,所以转一下: windows bat脚本for循环中对变量循环赋值 http://blog.csdn.net/u010161379/article/details/50956 ...
- JS打开新的窗口
一.使用JS打开新窗口 1. 超链接<a href="http://www.wumz.me" title="Mauger`s Blog">Welco ...
- js获取到的页面中的checkbox选中的项
需求描述:列表第一列是checkbox name和value都是id 想通过复选框的勾选状态来获取id,在js中获取 js代码: var checkId=$("input[name='che ...
- java----面对对象
面对对象: public class Demo { public static void main(String[] args){ Horse h = null; h = new Horse(); / ...