CF1175G
叉姐牛逼。
\(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的更多相关文章
随机推荐
- 【Spring】IoC容器 - Spring Bean作用域Scope(含SpringCloud中的RefreshScope )
前言 上一章学习了[依赖来源],本章主要讨论SpringBean的作用域,我们这里讨论的Bean的作用域,很大程度都是默认只讨论依赖来源为[Spring BeanDefinition]的作用域,因为在 ...
- LeetCode:BFS/DFS
BFS/DFS 在树专题和回溯算法中其实已经涉及到了BFS和DFS算法,这里单独提出再进一步学习一下 BFS 广度优先遍历 Breadth-First-Search 这部分的内容也主要是学习了labu ...
- UltraSoft - Beta - Scrum Meeting 9
Date: May 25th, 2020. Scrum 情况汇报 进度情况 组员 负责 今日进度 q2l PM.后端 记录Scrum Meeting Liuzh 前端 用户忘记密码界面初稿完成 Kkk ...
- mongodb的聚合操作
在mongodb中有时候我们需要对数据进行分析操作,比如一些统计操作,这个时候简单的查询操作(find)就搞不定这些需求,因此就需要使用 聚合框架(aggregation) 来完成.在mongodb ...
- Noip模拟80 2021.10.18
预计得分:5 实际得分:140?????????????? T1 邻面合并 我考场上没切掉的大水题....(证明我旁边的cty切掉了,并觉得很水) 然而贪心拿了六十,离谱,成功做到上一篇博客说的有勇气 ...
- [火星补锅] 非确定性有穷状态决策自动机练习题Vol.3 T3 && luogu P4211 [LNOI2014]LCA 题解
前言: 这题感觉还是很有意思.离线思路很奇妙.可能和二次离线有那么一点点相似?当然我不会二次离线我就不云了. 解析: 题目十分清真. 求一段连续区间内的所有点和某个给出的点的Lca的深度和. 首先可以 ...
- 助你上手Vue3全家桶之Vue-Router4教程
目录 1,前言 1,Router 2.1,跳转 2.2,打开新页面 3,Route 4,守卫 4.1,onBeforeRouteLeave 4.2,onBeforeRouteUpdate 4.3,路由 ...
- bash执行顺序:alias --> function --> builtin --> program
linux bash的执行顺序如下所示: 先 alias --> function --> builtin --> program 后 验证过程: 1,在bash shell中有内置 ...
- sql 多表联合查询更新
sqlserver: update A a set a.i = b.k from B b where a.key = b.key oracle : update A a set a.i = (sele ...
- cf 11D A Simple Task(状压DP)
题意: N个点构成的无向图,M条边描述这个无向图. 问这个无向图中共有多少个环. (1 ≤ n ≤ 19, 0 ≤ m) 思路: 例子: 4 6 1 2 1 3 1 4 2 3 2 4 3 4 答案: ...