点此看题面

大致题意: 你可以对一个序列进行\(k\)次分割,每次得分为两个块元素和的乘积,求总得分的最大值。

区间\(DPor\)斜率优化\(DP\)

这题目第一眼看上去感觉很明显是区间\(DP\)。

但是,一看数据范围,\(n\le100000\),这是要上天的节奏!

不过,再看\(m\le200\),比较显然应该是\(O(nm)\)的时间复杂度。

实际上,这题的确是可以用斜率优化\(DP\)来做到\(O(nm)\)的。

推性质

首先,我们要知道一个性质:将一个区间进行若干次分割,分割的顺序是不影响最后的总得分的

证明如下:

设要对一个区间进行\(2\)次分割,则分割完后有\(3\)个区间,每个区间的价值和分别为\(a_1,a_2,a_3\)。

则总共有两种分割顺序,得到的总得分分别为\(a_1·(a_2+a_3)+a_2·a_3\)和\((a_1+a_2)·a_3+a_1·a_2\)。

实际上,这两个式子化简后皆为\(a_1a_2+a_1a_3+a_2a_3\)。

而多次分割其实是同理的。

状态转移

这样一来,就不难想到针对这种问题的常见套路:设\(f_{i,j}\)表示在前\(i\)个数中割\(j\)次得到的最大总得分

状态转移方程如下:

\[f_{i,j}=f_{x,j-1}+sum_x*(sum_i-sum_x)\]

这应该是比较好理解的吧,就相当于枚举一个割的位置,总得分为该区间前半部分割\(j-1\)次的最大得分加上这两部分元素和的乘积

对于这种式子,比较显然可以斜率优化

将原式展开得:

\[f_{x,j-1}-sum_x*sum_x=-sum_x*sum_i+f_{i,j}\]

要注意在转移过程中可能会出现分母为\(0\)的情况,则需要给此时的斜率赋值为\(-INF\)。

由于要记方案,所以再用一个\(g\)数组记录下从哪个元素转移而来即可。

代码

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define Gmax(x,y) (x<(y)&&(x=(y)))
#define Gmin(x,y) (x>(y)&&(x=(y)))
#define abs(x) ((x)<0?-(x):(x))
#define swap(x,y) (x^=y^=x^=y)
#define uint unsigned int
#define LL long long
#define ull unsigned long long
#define INF 1e18
#define N 100000
#define M 200
using namespace std;
int n,m,sum[N+5];
class Class_FIO
{private:#define Fsize 100000#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)#define pc(ch) (void)(FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))int f,FoutSize,Top;char ch,Fin[Fsize],*A,*B,Fout[Fsize],Stack[Fsize];public:Class_FIO() {A=B=Fin;}inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));x*=f;}inline void read_digit(int &x) {while(!isdigit(x=tc()));x&=15;}inline void readc(char &x) {while(isspace(x=tc()));}inline void reads(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())&&~ch);}inline void write(LL x) {if(!x) return pc('0');x<0&&(pc('-'),x=-x);while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}inline void writec(char x) {pc(x);}inline void writes(string x) {for(register int i=0,len=x.length();i<len;++i) pc(x[i]);}inline void clear() {fwrite(Fout,1,FoutSize,stdout),FoutSize=0;}
}F;
class Class_SlopeDP
{private:#define A(x) (f[x][j-1]-1LL*sum[x]*sum[x])#define B(x) (-1LL*sum[x])#define S(x,y) (B(x)^B(y)?1.0*(A(y)-A(x))/(B(y)-B(x)):-INF)//对于分母为0的情况,返回-INF#define Slope (1LL*sum[i])int q[N+5],g[N+5][M+5];LL f[N+5][M+5];inline void PrintStep(int x,int y) {y&&(PrintStep(g[x][y-1],y-1),F.write(x),F.writec(' '),0);}//输出方案public:inline void Solve()//DP转移{register int i,j,H,T;for(j=1;j<=m;++j){for(q[H=T=1]=0,i=1;i<=n;++i)//每次记得清空队列{while(H<T&&S(q[H],q[H+1])<=Slope) ++H;f[i][j]=f[g[i][j]=q[H]][j-1]+1LL*sum[q[H]]*(sum[i]-sum[q[H]]);while(H<T&&S(q[T],i)<=S(q[T-1],q[T])) --T;q[++T]=i;}}}inline void Print() {F.write(f[n][m]),F.writec('\n'),PrintStep(g[n][m],m);}
}SlopeDP;
int main()
{register int i;for(F.read(n),F.read(m),i=1;i<=n;++i) F.read(sum[i]),sum[i]+=sum[i-1];return SlopeDP.Solve(),SlopeDP.Print(),F.clear(),0;
}

转载于:https://www.cnblogs.com/chenxiaoran666/p/Luogu3648.html

【洛谷3648】[APIO2014] 序列分割(斜率优化DP)相关推荐

  1. 洛谷P3648 [APIO2014]序列分割(斜率优化)

    传送门 没想到这种多个状态转移的还能用上斜率优化--学到了-- 首先我们可以发现,切的顺序对最终答案是没有影响的 比方说有一个序列$abc$,每一个字母都代表几个数字,那么先切$ab$再切$bc$,得 ...

  2. 洛谷4072 SDOI2016征途 (斜率优化+dp)

    首先根据题目中给的要求,推一下方差的柿子. \[v\times m^2 = m\times \sum x^2 - 2 \times sum \times sum +sum*sum\] 所以\(ans ...

  3. 洛谷 P3195 [HNOI2008]玩具装箱 —— 斜率优化

    This way 题意: 题解: 洛谷的题解就写的蛮好,首先对于斜率优化,先将它的转移方程写出来,然后对于只包含i的设为A,只包含j的设为B,然后对于含有A和B的项就是二元一次方程中的k和x 这个就可 ...

  4. [USACO18JAN]Lifeguards P 洛谷黑题,单调队列优化DP

    传送门:戳我 这道题有两个版本,S和P,S是K等于1的情况,显然可以用线段树水过. P版本就难了很多,洛谷黑题(NOI/NOI+/CTSC),嘿嘿. 我自己也不是很理解,照着题解写了一遍,然后悟到了一 ...

  5. 【洛谷P1430】序列取数【dp】

    题目大意: 题目链接:https://www.luogu.org/problemnew/show/P1430 给定一个长为n的整数序列,由A和B轮流取数(A先取).每个人可从序列的左端或右端取若干个数 ...

  6. 斜率优化dp 的简单入门

    不想写什么详细的讲解了...而且也觉得自己很难写过某大佬(大米饼),于是建议把他的 blog 先看一遍,然后自己加了几道题目以及解析...顺便建议看看算法竞赛(蓝皮书)的 0x5A 斜率优化(P294 ...

  7. YBTOJ洛谷P3195:玩具装箱(斜率优化dp)

    传送门 文章目录 前言 解析 代码 前言 斜率优化dp,就是利用斜率优化的dp (逃) 解析 第一道斜优的题 分析题目 设sumisum_isumi​为1-i的c的前缀和 容易写出dp转移式: dpi ...

  8. BZOJ3675: [Apio2014]序列分割

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

  9. 洛谷P3647 [APIO2014] 连珠线 题解

    洛谷P3647 [APIO2014] 连珠线 题解 题目链接:P3647 [APIO2014] 连珠线 题意: 在达芬奇时代,有一个流行的儿童游戏称为连珠线.当然,这个游戏是关于珠子和线的.线是红色或 ...

最新文章

  1. 从0开始搭建编程框架——主框架和源码
  2. 推荐一个比较好的SQL工具——SQL Prompt
  3. SQL 列转行、行转列 - 使用sqlite演示
  4. 如何使用图形界面Webmin管理linux服务器
  5. Java 分割字符串的方法String.split()底层原理
  6. 应该怎么学python_什么样的人适合学Python,应该怎么学?
  7. 如何:修改 Office Open XML 文档【转载】
  8. 【ArcGIS微课1000例】0021:ArcToolBox工具箱功能与环境概述
  9. frame框架 超链接
  10. 计算机常用控温算法,常用温度控制方法原理 -解决方案-华强电子网
  11. 将Access数据库导入到SQLite最简单最实用的方法 -转
  12. 当前主流的单元测试工具
  13. 【杂题总汇】HDU多校赛第十场 Videos
  14. ImageJ的单细胞荧光强度分析
  15. ssh关闭linux的网卡,linux操作系统修改网卡mac地址 ssh -X
  16. 10008---光环效应
  17. 数学建模(六) 主成分分析,聚类分析,对策论,马氏链
  18. 日本地震波及芯片产业链致价格走势难料
  19. 论文阅读-Boosting Data-driven Evolutionary Algorithm with Localized Data Generation
  20. 谷歌浏览器和火狐浏览器的12px字体显示大小不一样

热门文章

  1. 编程入门python语言是多大孩子学的-如何看待将Python作为少儿编程的基础语言?...
  2. 常用python编程软件-学习编程语言常用的10个工具、库——每个程序员都应该知道...
  3. 如何自学python爬虫-零基础入门Python爬虫不知道怎么学?这是入门的完整教程
  4. python详细安装教程linux-Linux环境下Python的安装方法
  5. python基础语法手册format-python基础知识之格式化
  6. 如何系统的自学python 知乎-如何系统地自学 Python?
  7. python怎么画条形图-python绘制条形图方法代码详解
  8. python开发的优秀界面-八款常用的 Python GUI 开发框架推荐
  9. 从零开始学python网络爬虫-从零开始学Python 三(网络爬虫)
  10. python真的很厉害吗-python为什么这么牛?Python真有这么好的前景?