1 条题解
-
0
自动搬运
来自洛谷,原作者为

灵乌路空
已退役 | 东方众OIer交流群 (幻想乡养老院) : 691090556搬运于
2025-08-24 21:28:21,当前版本为作者最后更新于2019-05-08 15:57:56,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
先无良宣传一下博客
文章列表 - 地灵殿 - 洛谷博客: 全部重构
感谢 胖虎x 与 Grass2_Ofalen 提出问题
删除了之前由于数据水卡过去的 优先队列做法
知识点 : , 单调队列优化
原题面
题目要求 :
给定一长度为 的数列 , 第 项为
以第一项为起点 , 对于当前的位置
可以转移到: 中任意一位置
并且获得当前位置上 数的价值 .求 : 当位置 时可以取得的 最大价值和
分析题意:
很显然的 .
设 为: 到达位置 时最大的价值和 , 则状态转移方程如下 :
- 我会暴力
枚举每一位置 , 枚举每一可转移到该位置的 位置, 暴力进行转移
复杂度 , 取得了 分的好成绩 (大雾)
考虑优化 :
-
转移到 位置 的位置 , 为区间 中 , 最大的位置
-
转移到 位置 的位置 , 为区间 中 , 最大的位置
-
转移到 位置 的位置 , 为区间 中 , 最大的位置
后两个区间 , 都可以通过 上一个区间 右移一个单位 得到
这不禁让我们想到了另一道题 : P1886 滑动窗口
如果您还未学习过单调队列 , 推荐这篇文章:
【洛谷日报#9】 [Sweetlemon] 朝花中学OI队的奋斗历程——浅谈单调队列这种 滑动窗口型 最值问题 , 显然 , 可以通过 单调队列 来进行维护 .
由上 , 我们便找到了一种合适 优化方法 : 单调队列优化 .
算法实现 :
顺序枚举 的每一个位置 .
- 将能够转移到 的最靠右的位置 插入单调队列中
- 删除 单调队列首 不能转移到 的位置
- 查询当前单调队列首的位置 , 即为能够转移到 的价值最大的位置
- 若 , 说明位置 能够跳到对岸 , 对此类位置的权值和取最大值, 即为答案
附 代码 :
//By:Luckyblock //バカって言うなぁ #include <cstdio> #include <cstring> #include <ctype.h> #define max(a, b) (a > b ? a : b) const int MARX = 2e5 + 10; const int INF = 2e9; //============================================================= int N, L, R, A[MARX], ans, f[MARX];//设 f[i]: 到达位置 i 时最大的价值和 int que[MARX], head = 1, tail = 1;//单调队列, 内部元素为位置 //============================================================= inline int read() { int s = 1, w = 0; char ch = getchar(); for(; !isdigit(ch); ch = getchar()) if(ch == '-') s = -1; for(; isdigit(ch); ch = getchar()) w = (w << 1) + (w << 3) + (ch ^ '0'); return s * w; } void Insert(int i)//插入操作 { for(; f[i] >= f[que[tail]] && tail >= head; ) tail --;//弹出权值和较小的 队尾元素 que[++ tail] = i;//入队 } int query(int x) { for(; que[head] + R < x; ) head ++;//弹出队首 不可到达x位置的 不合法元素 return que[head];//回答询问 } //============================================================= int main() { memset(f, 128, sizeof(f));//初始化极小值 (每个字节赋128会导致自然溢出 f[0] = 0, ans = - INF; //初始化, 将0位置权值和 赋为0 N = read(), L = read(), R = read(); for(int i = 0; i <= N; i ++) A[i] = read(); for(int i = L; i <= N; i ++) { Insert(i - L); //将最后一个 能够转移到i的位置 加入单调队列 int from = query(i);//找到队首 权值和最大的位置 f[i] = f[from] + A[i];//进行转移 if(i + R > N) ans = max(ans, f[i]);//判断i能够跳到对岸, 计算答案 } printf("%d", ans); return 0; }
附评论区的 数据 , 重构题解后已过
testdata1.in:
5 3 4 0 1 2 3 4 5testdata1.out
4testdata2.in:
7 4 4 0 1 -4 -2 2 -5 3 2testdata2.out:
2
完成了这篇题解 , 东方众信仰
- 我会暴力
- 1
信息
- ID
- 703
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者