[APIO2014]序列分割 --- 斜率优化DP
[APIO2014]序列分割
题目大意:
你正在玩一个关于长度为\(n\)的非负整数序列的游戏。这个游戏中你需要把序列分成\(k+1\)个非空的块。为了得到\(k+1\)块,你需要重复下面的操作\(k\)次:
选择一个有超过一个元素的块(初始时你只有一块,即整个序列)
选择两个相邻元素把这个块从中间分开,得到两个非空的块。
每次操作后你将获得那两个新产生的块的元素和的乘积的分数。你想要最大化最后的总得分。
\(n<=10^{5},k<=200\)
首先划分完\(k\)块后,发现非常像线性DP模型
自然地想,是不是分数跟划的顺序无关?
可以证明是的(归纳法)
那么,设
\(dp(i,j)\)表示枚举到了\(i\),第\(1...i\)切了几刀的最大收益。
有\(dp(i,j)=max(dp(k,j-1)+sum[k]*(sum[i]-sum[k]))(1<=k<=i-1)\)
那么展开式子,化为斜率优化的式子:
\(-dp(k,j-1)=sum[k]*sum[i]-sum[k]^{2}-dp(i,j)\)
其中\(k\)为\(sum[k]\),单调递增
其中\(x\)为\(sum[i]\),单调递增
要使\(dp(i,j)\)最大,因此维护下凸包,那么可以使用单调队列
空间滚一下就好
空间复杂度:\(O(n)\)(忽略记录决策点)
时间复杂度:\(O(nk)\)
注:被宏定义坑了很久。。。
#include<cstdio>
#include<cstring>
#define sid 100050
#define dd double
#define ll long long
#define ri register int
using namespace std; #define getchar() *S ++
char RR[], *S = RR;
inline int read(){
int p = , w = ;
char c = getchar();
while(c > '' || c < '') {
if(c == '-') w = -;
c = getchar();
}
while(c >= '' && c <= '') {
p = p * + c - '';
c = getchar();
}
return p * w;
} ll sum[sid], dp[][sid];
int lst[][sid], q[sid], n, k;
bool now = , pre = ; #define x(g) sum[(g)]
#define y(g) (sum[(g)]*sum[(g)]-dp[pre][(g)])
inline dd s(int i, int j) {
if(x(i) == x(j)) return -1e18;
return (dd)(y(i) - y(j)) / (dd)(x(i) - x(j));
} int main() {
fread(RR, , sizeof(RR), stdin);
n = read(); k = read();
for(ri i = ; i <= n; i ++) sum[i] = sum[i - ] + read();
for(ri j = ; j <= k; j ++) {
int fr = , to = ; now ^= ; pre ^= ;
for(ri i = ; i <= n; i ++) {
while(fr + <= to && s(q[fr], q[fr + ]) <= sum[i]) fr ++;
dp[now][i] = dp[pre][q[fr]] + sum[q[fr]] * (sum[i] - sum[q[fr]]);
lst[j][i]=q[fr];
while(fr + <= to && s(q[to - ], q[to]) >= s(q[to], i)) to --;
q[++ to] = i;
}
}
printf("%lld\n",dp[now][n]);
int e = n;
for(ri i = k; i >= ; i --) {
e = lst[i][e]; printf("%d ", e);
}
return ;
}
序列分割
[APIO2014]序列分割 --- 斜率优化DP的更多相关文章
- bzoj3675[Apio2014]序列分割 斜率优化dp
3675: [Apio2014]序列分割 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 3508 Solved: 1402[Submit][Stat ...
- 【bzoj3675】[Apio2014]序列分割 斜率优化dp
原文地址:http://www.cnblogs.com/GXZlegend/p/6835179.html 题目描述 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列 ...
- BZOJ 3675 [Apio2014]序列分割 (斜率优化DP)
洛谷传送门 题目大意:让你把序列切割k次,每次切割你能获得 这一整块两侧数字和的乘积 的分数,求最大的分数并输出切割方案 神题= = 搞了半天也没有想到切割顺序竟然和答案无关...我太弱了 证明很简单 ...
- BZOJ 3675 APIO2014 序列切割 斜率优化DP
题意:链接 方法:斜率优化DP 解析:这题BZ的数据我也是跪了,特意去网上找到当年的数据后面二十个最大的点都过了.就是过不了BZ. 看到这道题自己第一发DP是这么推得: 设f[i][j]是第j次分第i ...
- P3648 [APIO2014]序列分割 斜率优化
题解:斜率优化\(DP\) 提交:\(2\)次(特意没开\(long\ long\),然后就死了) 题解: 好的先把自己的式子推了出来: 朴素: 定义\(f[i][j]\)表示前\(i\)个数进行\( ...
- 【BZOJ3675】【APIO2014】序列分割 [斜率优化DP]
序列分割 Time Limit: 40 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description 小H最近迷上了一个分隔序列的游戏. ...
- BZOJ3675: [Apio2014]序列分割(斜率优化)
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 4186 Solved: 1629[Submit][Status][Discuss] Descript ...
- BZOJ 3675: 序列分割 (斜率优化dp)
Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序列,小H需要重复k次以下的步骤: 1.小H首 ...
- BZOJ 3675: [Apio2014]序列分割( dp + 斜率优化 )
WA了一版... 切点确定的话, 顺序是不会影响结果的..所以可以dp dp(i, k) = max(dp(j, k-1) + (sumn - sumi) * (sumi - sumj)) 然后斜率优 ...
随机推荐
- 【NOI2017】游戏 2-sat算法
[题目]LibreOJ [题意]n场游戏,有三种车ABC,给定长度为n的字符串,'a'表示不能选A,'b''c'同理,'x'表示不限,至多d个'x'.有m个限制(i,hi,j,hj)表示如果第i场选择 ...
- NYOJ 1073 最大值 (模拟)
题目链接 输入N个数,M次查询. 每次查询给出一个数x. 要求:每次查询输出前x个数中第i小的数.(i为第i次查询) 你可以假设M <= N,Xi <= Xi+1 <= Xi+2 & ...
- 天梯赛 L2-010 排座位 (并查集)
布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位.无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席. 输入格式: ...
- ajax技术整理总结(1)
1.创建ajax对象 var xhr=new XMLHttpRequest(); 4.监听状态信息 xhr.onreadystatechange=function(){ //4接收完毕 ){ docu ...
- webconfig的配置解析
<?xml version="1.0"?> <!--注意: 除了手动编辑此文件以外,您还可以使用 Web 管理工具来配置应用程序的设置.可以使用 Visual S ...
- python基础===python自带idle的快捷键
Ctrl + [ Ctrl + ] 缩进代码Alt+3 Alt+4 注释.取消注释代码行Alt+5 Alt+6 切换缩进方式 空格<=>TabAlt+/ 单词完成,只要文中出现过,就可 ...
- CentOS7.4 安装 oracle12c
安装依赖 yum install -y binutils.x86_64 compat-libcap1.x86_64 gcc.x86_64 gcc-c++.x86_64 glibc.i686 glibc ...
- 根据名字杀死进程Killall
Killall命令可以用来给一个特定的进程发送一个信号.这个信号默认情况下是SIGTERM,但也可以由killall命令使用参数来指定其它信号.现在让我们通过一些实际的例子来看看这个命令的实际用法. ...
- C语言花括号
由于C语言本身就是函数式语言,说白了,C程序就是由函数构成的! 所以花括号肯定是用在函数之中,包括函数中的各种流程控制语句中. 实际上,C程序中花括号{}的作用:就是把多个单条语句用花括号{}括起来组 ...
- 20165301 2017-2018-2 《Java程序设计》第六周学习总结
20165301 2017-2018-2 <Java程序设计>第六周学习总结 教材学习内容总结 第七章:常用实类 String类 构造String对象 常量对象 String对象 Stri ...