好久没写博客了……我终于回来了……

dp总是令我很头疼的问题之一,然而我还是要学一下怎么优化它。

下面请看一道题吧:

[bzoj3675][Apio2014]序列分割

试题描述

小H最近迷上了一个分割序列的游戏。在这个游戏里,小H需要将一个长度为N的非负整数序列分割成k+l个非空的子序列。为了得到k+l个子序列,小H将重复进行七次以下的步骤:

1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的序列一一也就是一开始得到的整个序列);

2.选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新序列。

每次进行上述步骤之后,小H将会得到一定的分数。这个分数为两个新序列中元素和的乘积。小H希望选择一种最佳的分割方案,使得k轮(次)之后,小H的总得分最大。

输入

输入文件的第一行包含两个整数n和尼(k+1≤n)。
第二行包含n个非负整数a1,n2….,an(0≤ai≤10^4),表示一开始小H得到的序列。

输出

一行包含一个整数,为小H可以得到的最大得分。

输入示例

      

输出示例


样例解释

在样例中,小H可以通过如下3轮操作得到108分:

1.-开始小H有一个序列(4,1,3,4,0,2,3)。小H选择在第1个数之后的位置将序列分成两部分,并得到4×(1+3+4+0+2+3)=52分。

2.这一轮开始时小H有两个序列:(4),(1,3,4,0,2,3)。小H选择在第3个数字之后的位置将第二个序列分成两部分,并得到(1+3)×(4+0+2+3)=36分。

3.这一轮开始时小H有三个序列:(4),(1,3),(4,0,2,3)。小H选择在第5个数字之后的位置将第三个序列分成两部分,并得到(4+0)×(2+3)=20分。

经过上述三轮操作,小H将会得到四个子序列:(4),(1,3),(4,0),(2,3)并总共得到52+36+20=108分。

数据范围

100%数据满足2≤n≤100000,1≤k≤min(n -1,200)。

题解

直至把这题A了也不明白“小H将重复进行七次以下的步骤”,为啥是七次以下,所以打了个删除线,希望读者不要多虑。

设F(i, j)表示考虑序列前i个元素,操作了j次的最大得分。

可得转移:F(i, j) = max{ f(k, j - 1) + sum[k] · (sum[i] - sum[k]) | 1 ≤ k < i },sum[i]表示序列第i位的前缀和。

但是这个玩意是O(n2·k)的,太慢了,受不了,于是需要斜率优化。

并且,为了省空间,我们开一个滚动数组,令f(i)表示状态F(i, j)中j为当前操作步数时的方案数(即f(i) = F(i, j)),g(i)表示状态F(i, j)中j为当前操作步数减1时的方案数(即g(i) = F(i, j - 1))。那么f(i) = max{ g(j) + sum[j] * (sum[i] - sum[j]) | 1 ≤ j < i }

假设上一次操作在位置j发生的方案比在位置k发生的方案更优且j > k,则有g(j) + sum[j] · (sum[i] - sum[j]) > g(k) + sum[k] · (sum[i] - sum[k])最后可推出(g(j) - g(k) + sum[k]2 - sum[j]2) / (sum[k] - sum[j]) < sum[i] (注意sum[k] - sum[j] < 0,移项时要变号)注意到sum[i]是单调不降的,所以我们可以用一个单调队列维护变号q[1~n],使得 q[i] < q[i+1] 且 g(q[i+1])比g(q[i])更优。令slop(j, k) = (g(j) - g(k) + sum[k]2 - sum[j]2) / (sum[k] - sum[j]) < sum[i],则当slop(i, q[r]) < slop(q[r], q[r-1])时,q[r]已经没必要存在了。

证明:设q[r]在处理到位置k时被加进队列中,

  那么显然k < i

  因为g(q[r])比g(q[r-1])更优,所以slop(q[r], q[r-1]) < sum[k]

又sum[i]单调递增,所以

  slop(i, q[r]) < slop(q[r], q[r-1]) < sum[k] < sum[i]

注意到slop(i, q[r]) < sum[i],所以i一定比q[r]更优,把q[r]抛弃掉。

马丹这题要开long long,搞得我半天没有调过去……

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; const int BufferSize = << ;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
if(Head == tail) {
int l = fread(buffer, , BufferSize, stdin);
tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = , f = ; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -; c = Getchar(); }
while(isdigit(c)){ x = x * + c - ''; c = Getchar(); }
return x * f;
} #define maxn 100010
#define LL long long
int n, K, l, r, q[maxn], cur;
LL f[maxn][], sum[maxn]; double sqr(int x) { return (double)x * x; }
double slop(int j, int k) {
return (f[j][cur^] - f[k][cur^] + sqr(sum[k]) - sqr(sum[j])) / (double)(sum[k] - sum[j]);
} int main() {
n = read(); K = read();
for(int i = ; i <= n; i++) sum[i] = sum[i-] + read(); int t = ;
for(int i = ; i <= n; i++) if(sum[i] != sum[i+]) sum[++t] = sum[i];
n = t;
for(int j = ; j <= K; j++) {
cur ^= ;
l = ; r = ;
for(int i = j; i <= n; i++) {
while(l < r && slop(q[l+], q[l]) < (double)sum[i]) l++;
f[i][cur] = f[q[l]][cur^] + sum[q[l]] * (sum[i] - sum[q[l]]);
while(l < r && slop(i, q[r]) < slop(q[r], q[r-])) r--;
q[++r] = i;
}
} printf("%lld\n", f[n][cur]); return ;
}

代码在这里!!

新技能get——斜率优化的更多相关文章

  1. POJ 2018 Best Cow Fences (二分答案构造新权值 or 斜率优化)

    $ POJ~2018~Best~Cow~ Fences $(二分答案构造新权值) $ solution: $ 题目大意: 给定正整数数列 $ A $ ,求一个平均数最大的长度不小于 $ L $ 的子段 ...

  2. DP的各种优化(动态规划,决策单调性,斜率优化,带权二分,单调栈,单调队列)

    前缀和优化 当DP过程中需要反复从一个求和式转移的话,可以先把它预处理一下.运算一般都要满足可减性. 比较naive就不展开了. 题目 [Todo]洛谷P2513 [HAOI2009]逆序对数列 [D ...

  3. 【BZOJ3672】[Noi2014]购票 树分治+斜率优化

    [BZOJ3672][Noi2014]购票 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.       ...

  4. [斜率优化DP]【学习笔记】【更新中】

    参考资料: 1.元旦集训的课件已经很好了 http://files.cnblogs.com/files/candy99/dp.pdf 2.http://www.cnblogs.com/MashiroS ...

  5. 单调队列 && 斜率优化dp 专题

    首先得讲一下单调队列,顾名思义,单调队列就是队列中的每个元素具有单调性,如果是单调递增队列,那么每个元素都是单调递增的,反正,亦然. 那么如何对单调队列进行操作呢? 是这样的:对于单调队列而言,队首和 ...

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

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

  7. 5332盛照宗 如何获取新技能+c语言学习调查

    如何获取新技能+c语言学习调查 你有什么技能比大多人(超过90%以上)更好? 如果问我有没有什么技能比大多数人,并且是90%的人好,我还真不敢说有,因为世界上有70亿人,要比63亿人做的好才行啊.我也 ...

  8. 腾讯优测干货精选| 安卓开发新技能Get -常用必备小工具汇总

    文/腾讯公司 陈江峰 优测小优有话说: 移动研发及测试干货哪里找?腾讯优测-优社区你值得拥有~ 开发同学们都知道,安卓开发路上会碰到很多艰难险阻,一不小心就被KO.这时候,没有新技能傍身怎么行?今天我 ...

  9. 动态规划(斜率优化):BZOJ 3675 [Apio2014]序列分割

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

随机推荐

  1. Ajax Post 类实例

    以前总是ajax请求是这样的 data:"a=1&b=2&c=3..." 而Controller也总是这样的 Action(int a,int b,int c) 很 ...

  2. 10月16日下午MySQL数据库CRUD操作(增加、删除、修改、查询)

    1.MySQL注释语法--,# 2.2.后缀是.sql的文件是数据库查询文件. 3.保存查询. 关闭查询时会弹出提示是否保存,保存的是这段文字,不是表格(只要是执行成功了表格已经建立了).保存以后下次 ...

  3. Linux下htop的使用

    linux top命令VIRT,RES,SHR,DATA的含义 第1行-第4行:显示CPU当前的运行负载,有几核就有几行,我的是4核 Mem:显示内存的使用情况,3887M大概是3.8G,此时的Mem ...

  4. OpenGL Tutorial

    https://open.gl https://www.processing.org/tutorials/pshader/

  5. js控制全屏窗口

    <script src="__PUBLIC__/Js/jquery.min.js"></script> <script type="text ...

  6. Why is applicationhost.config still being added to source control even thought it's in gitignore

      Why is applicationhost.config still being added to source control even thought it's in gitignore g ...

  7. Sqlserver2008 表分区教程

    先声明..Sql2008只有企业版才能够搞这个表分区.其他版本请自觉更改.. 哥在这里费了很长时间劲..结果还是老老实实的重装.. 表分区定义 一般情况下,我们建立数据库表时,表数据都存放在一个文件里 ...

  8. Python开发【第十九篇】:Python操作MySQL

    本篇对于Python操作MySQL主要使用两种方式: 原生模块 pymsql ORM框架 SQLAchemy pymsql pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb ...

  9. NERD_commenter——VIM批量注释与反注释插件

    转自:http://www.xefan.com/archives/83568.html 这是对程序员非常实用的一款插件,支持多种语言的补全,还支持单行注释,批量注释,等各种命令映射. 使用方法,先下载 ...

  10. emlog在nginx中添加rewrite规则

    rewrite ^/(post|record|sort|author|page)-([-]+)\.html$ /index.php?$=$; rewrite ^/tag-(.+)\.html$ /in ...