叉姐牛逼。

\(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]);
}

CF1175G的更多相关文章

随机推荐

  1. 【UE4】虚幻引擎技术直播汇总(含中英文直播)

    B站虚幻引擎官方账号 中文直播 [中文直播]第35期 | 使用GIS在UE中创造真实地球风貌 | Epic 周澄清 [中文直播]第34期 | 包教包会的Epic MegaGrants申请之道 | Ep ...

  2. Java Filter型内存马的学习与实践

    完全参考:https://www.cnblogs.com/nice0e3/p/14622879.html 这篇笔记,来源逗神的指点,让我去了解了内存马,这篇笔记记录的是filter类型的内存马 内存马 ...

  3. Matlab+Qt开发笔记(一):matlab搭建Qt开发matlib环境以及Demo测试

    前言   做一些数据处理软件,使用matlab文件,.mat文件.   准备条件   安装matlab2016,发现是vs 12(是vs2011版本),Qt5.9.3是支持vs 14(是vs2015版 ...

  4. pycharm基本使用python的注释语法

    pychram基本使用 1.主题选择 file settings Editor color Scheme 2.pycharm切换解释器 file settings Project Python Int ...

  5. ELK集群之kibana(4)

    kibane安装及基础使用 Kibana的安装 Kibana包含前端展示.es操作简化 yum localinstall kibana-7.6.2-x86_64.rpm -y Kibana配置修改ki ...

  6. C++ Qt 项目实战(一)之文本编辑器

    文本编辑器例图 项目开发环境 系统版本:windows10 QT 版本: 5.9.9 开发语言:C++ 已实现功能 文件操作:新建,打开,保存,另存为,打印,退出 编辑操作:复制,粘贴,剪切,查找,替 ...

  7. Java学到什么程度能找到一份还不错的工作

    我的读者里有很多 Java 新人,新人是指正在学 Java 的.以及工作时间不长的年轻人,他们经常问我一个问题: Java 学到什么程度才能找到一份还不错的工作? 今天我就从我自己面试新人的角度来回答 ...

  8. v-bind使用

    v-bind基本使用 动态地绑定一个或多个属性,或者绑定一个组件 prop 到表达式. 语法:v-bind:属性名 = 属性值 <!-- 绑定一个 attribute --> <im ...

  9. springboot入门之版本依赖和自动配置原理

    前言 Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that ...

  10. spring security 之自定义表单登录源码跟踪

    ​ 上一节我们跟踪了security的默认登录页的源码,可以参考这里:https://www.cnblogs.com/process-h/p/15522267.html 这节我们来看看如何自定义单表认 ...