\(\text{Problem}\)

大意就是优化这样一个 \(dp\)

\[f_{i}=\max f[j]+(i-j) \cdot (i-j-1)
\]

\(L[i] \le j < i,n\le 5 \times 10^6\)

\(L[i]\) 给出且满足 \(L[x] \le L[x+1]\)

\(\text{Solution}\)

本做法经大佬指点

\(O(n \log n)\) 时限有 \(2.5s\) 且 \(\log\) 来源于树状数组是可以过的

当然本题存在线性做法 (然而没懂)

显然斜率优化,最大值维护上凸包

然而你会发现 \(L\) 的限制很可恨,对于入队的点,维护凸包时弹掉的点可能是以后的最优决策(因为\(L\)可以让你取不到没限制时的最优点,不得不往后选在 \(L\) 范围内的点,而这些点可能被维护凸包时弹掉了)

但要明确一点,如果你把可以用的决策点合成一块后维护上凸包,就可以用常规斜率优化弹点寻找最优点

那么我们如何快速把 \([L[i],i)\) 的所有决策提出来维护凸包?

再明确一件事,把 \([L[i],i)\) 分成连续的几块,对每块的最优值取最大值是等价于整块的最优值的(显然)

那么如何优秀地分块

注意到树状数组本身就是个前缀和,且拆成了 \(\log\) 块,可以让树状数组上每个点 \(x\) 维护一个区间的凸包(每个点维护个单调栈,开 \(\text{vector}\))

本题维护后缀和

这样就可以成功了

\(\text{Code}\)

#include <cstdio>
#include <vector>
#include <iostream>
#define LL long long
#define re register
using namespace std; const int N = 5e6 + 5;
int n, L[N];
LL f[N]; inline int read(int &x)
{
x = 0; char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
} inline double slope(int j, int k)
{
return 1.0 * (f[j] + 1LL * j * j + j - f[k] - 1LL * k * k - k) / (j - k);
}
struct Stack{
vector<int> Q;
inline int size(){return Q.size();}
inline int top1(){return Q[Q.size() - 1];}
inline int top2(){return Q[Q.size() - 2];}
inline void pop(){Q.pop_back();}
inline void push(int x){Q.push_back(x);}
};
struct BIT{
Stack t[N];
inline int lowbit(int x){return x & (-x);}
inline LL calc(int i, int j)
{
return f[j] + 1LL * (i - j) * (i - j - 1);
}
inline LL query(int x, int k)
{
LL res = 0;
for(; x <= n; x += lowbit(x))
{
while (t[x].size() > 1 && slope(t[x].top2(), t[x].top1()) < k) t[x].pop();
if (t[x].size()) res = max(res, calc(k / 2, t[x].top1()));
}
return res;
}
inline void insert(int i)
{
for(re int x = i; x; x -= lowbit(x))
{
while (t[x].size() > 1 && slope(t[x].top2(), t[x].top1()) < slope(t[x].top1(), i)) t[x].pop();
t[x].push(i);
}
}
}T; int main()
{
freopen("jump.in", "r", stdin), freopen("jump.out", "w", stdout);
read(n);
for(re int i = 2; i <= n + 1; i++) read(L[i]), ++L[i];
T.insert(1);
for(re int i = 2; i <= n + 1; i++) f[i] = T.query(L[i], 2 * i), T.insert(i);
printf("%lld\n", f[n + 1]);
}

最新文章

  1. Html5 直接插入排序
  2. Enterprise Solution 2.2 开发帮助文档集合
  3. SQLite的介绍 操作Sqlite 具体实例
  4. (转)每天一个Linux命令(6):mv
  5. C#面向对象(一) 封装
  6. sql获取每门课程成绩最好的学生信息
  7. webapp 性能优化
  8. node传统读取文件和promise,async await,
  9. 第二章 函数编程&amp;常用标准库
  10. Session variables lost after the call of Response.Redirect method
  11. Vue:如何在vue-cli中创建并引入自定义组件
  12. Python 定值类
  13. BZOJ.4293.[PA2015]Siano(线段树)
  14. python自学第6天,文件修改,字符编码
  15. kbmmw 5.0 中的REST 服务
  16. 如何用NAnt管理单文件程序仓库
  17. sql的行转列(PIVOT)与列转行(UNPIVOT) webapi 跨域问题 Dapper 链式查询 扩展 T4 代码生成 Demo (抽奖程序)
  18. python if-elif-else 结构判断输入值处于何种年龄段
  19. 打开palette控制面板
  20. ubuntu查看进程端口号及运行的程序

热门文章

  1. js文字无限循环向上滚动
  2. 数电第五周周结_by_yc
  3. WEB入门——信息搜集1-20
  4. JuiceFS CSI Driver 常见问题排查指南
  5. Jmeter 模拟http发送zip文件
  6. Octave/Matlab初步学习
  7. LeetCode HOT 100:子集(简单易懂的回溯)
  8. HTML笨方法仿写站酷
  9. django中只使用ModleForm的表单验证,而不使用ModleForm来渲染
  10. [ 赛后总结 ] CSP-J 2022