叉姐牛逼。

\(f_{k,i} = \min_{0\leq j <i}{f_{k - 1,j} + RMQ(j + 1,i) * (i - j)}\)

我们考虑在序列上分治一波。

按照\(m\)切开,\(i >= m\),

我们需要找到

\(\min_{0\leq j < m} f_{k - 1,j} + \max{(suf[j],pre[i])} * (i - j)\)

然后我们发现此时\(suf[j]\)具有单调性。

我们可以分类讨论一下。

\(suf_j \leq pre_i\)

我们需要找到

\(\min_j g_j - pre[i] * j\)

否则

我们需要找到

\(min_j(g_j - suf_j * j) + i _suf[j]\)

考虑分治加单调栈处理。

叉姐牛逼。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 20001
#define INF 400000005 struct Line{
int k,b;
int val(int x){return k * x + b;}
}; inline bool check(Line u,Line v,Line w){
return 1ll * (v.b - u.b) * (v.k - w.k) < 1ll * (w.b - v.b) * (u.k - v.k);
} inline void qmin(int &x,int a){x = (x > a) ? a : x;} int n,a[N],dp[2][N],suf[N],pre[N];
Line stack[N]; #define m ((l + r) >> 1) inline void work(int *pdp,int *dp,int l,int r){
if(l < r){
suf[m] = 0;
for (int i = m; i > l; --i) {
suf[i - 1] = std::max(a[i], suf[i]);
}
pre[m] = 0;
for (int i = m + 1; i <= r; ++i) {
pre[i] = std::max(pre[i - 1], a[i]);
}
for (int i = m + 1, bot = n, j = m; i <= r; ++i) {
while (j >= l && suf[j] <= pre[i]) {
const Line line{-j, pdp[j]};
while (bot + 1 < n && !check(line, stack[bot], stack[bot + 1])) {
bot++;
}
stack[--bot] = line;
j--;
}
int x = pre[i];
while (bot + 1 < n && stack[bot].val(x) > stack[bot + 1].val(x)) {
bot++;
}
qmin(dp[i], stack[bot].val(x) + i * pre[i]);
}
for (int i = r, top = -1, j = l; i > m; --i) {
while (j <= m && suf[j] >= pre[i]) {
Line line{suf[j], pdp[j] - j * suf[j]};
j++;
while (j <= m && suf[j] == line.k) {
line.b = std::min(line.b, pdp[j] - j * suf[j]);
j++;
}
while (top - 1 >= 0 && !check(stack[top - 1], stack[top], line)) {
top--;
}
stack[++top] = line;
}
int x = i;
while (top - 1 >= 0 && stack[top - 1].val(x) < stack[top].val(x)) {
top--;
}
if (~top) {
qmin(dp[i], stack[top].val(x));
}
}
work(pdp, dp, l, m);
work(pdp, dp, m + 1, r);
}
} int main() {
int M;
scanf("%d%d", &n, &M);
for (int i = 1; i <= n; ++i) {
scanf("%d", a + i);
}
dp[0][0] = 0;
std::fill(dp[0] + 1, dp[0] + n + 1, INF);
for (int j = 0; j < M; ++j) {
std::fill(dp[(j + 1) & 1], dp[(j + 1) & 1] + (n + 1), INF);
work(dp[j & 1], dp[(j + 1) & 1], 0, n);
}
printf("%d\n", dp[M & 1][n]);
}

最新文章

  1. 读书笔记--SQL必知必会10--分组数据
  2. python ImportError: No module named builtins
  3. [LeetCode]Lowest Common Ancestor of a Binary Search Tree
  4. css之选择器篇
  5. git 基本配置及使用
  6. Jquery学习笔记:利用jquery获取select下拉框的值
  7. 小程序---根据数据库反向生成java文件
  8. JAVA解析XML的四种方式
  9. setvbuf
  10. python 面向对象简单理解
  11. axis2 webservices 411错误解决办法
  12. 查看错误日志发现有两个警告(ignored in --skip-name-resolve mode)
  13. JavaScript———从setTimeout与setInterval到AJAX异步
  14. Office办公软件(Excel PPT Word)使用整理
  15. Java对象中的finalize()方法使用说明
  16. 201521123060 《Java程序设计》第3周学习总结
  17. win10解决乱码问题
  18. HDU5135 dfs搜索 枚举种数
  19. 进军ABP第一天:ABP理论知识
  20. Redis 学习笔记2:redis.conf配置文件详解

热门文章

  1. NX9.0和NX10.0做自定义操作可以用的函数
  2. Java:常用的容器小记
  3. 注解,@Qualifier+@Autowired 和 @Resource
  4. [技术博客]Django框架-后端的搭建
  5. websocket入门案例(echo)
  6. activiti流程图上获取各节点的信息获取
  7. Noip模拟70 2021.10.6
  8. MySQL怎么缓解读的压力的?---buffer pool
  9. SpringBoot 全局异常拦截捕获处理
  10. mongodb安装教程(一)