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

retep
离谱!世界太离谱了!(关注必互关)搬运于
2025-08-24 22:39:08,当前版本为作者最后更新于2022-07-25 01:00:39,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目简述
你有一个长度为 的序列 ,它的一个区间 的价值为:
$\max\{a_l,a_{l+1},\cdots,a_r\}-\min\{a_l,a_{l+1},\cdots,a_r\}-r+l-1$。
求这个序列价值最大的子区间并输出这个价值。
数据范围:,
题目传送门:P8446 虹色的北斗七星
题目分析
这是道最优化问题,关键点在于对问题的转化。
题目中最显而易见的一点是 与 的位置一定是该区间的两个端点。
说实话这题本蒟蒻在比赛时想了很久,从动态规划到二分答案甚至连分治都考虑过,不过全部以不可行告终
要不是普及组不能超纲,我肯定浪费更多时间。我发现自己在之前的思考中都潜意识地将 视作一个整体,也就是区间的长度,毕竟题目中也是用长度的意义来叙述的。
意识到这点后我开始想,是不是可以将 分开呢? 很好说,只是个常量。关键在于 ,它俩其中一个是 的下标,另一个则是 的下标。
如果可以将 与 和 与 融合在一起就好了,因为那样的话就不用再受区间长度所困扰,只要求最大值和最小值就行了。可惜的是我们并不知道 和 哪个对应 哪个对应 ......
于是乎,分类讨论!
-
当 对应的下标是 ,也就是 在 右边时:
-
当 对应的下标是 ,也就是 在 左边时:
解释一下,如果是第一种情况的话,我们建立 数组,使 ,然后计算区间价值时,直接计算:
可以看出这时算出来的值正好是区间的价值。第二种情况的话使 然后同理。
到这儿,我们已经可以将原问题转换为两个子问题了:
-
,求 的最大值,保证 。
-
,求 的最大值,保证 。
最后将两个子问题合并,既取其中的最大值,就得到了问题的最终答案。
code
#include<bits/stdc++.h> #define N 4000005 #define ll long long using namespace std; int n,a[N],b[N],ans=-1; inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int main(){ n=read(); for(int i=1;i<=n;i++) a[i]=read(),b[i]=a[i]-i; for(int i=1,mn=1e9;i<=n;i++){ mn=min(b[i],mn); ans=max(ans,b[i]-mn); b[i]=a[i]+i; } for(int i=1,mx=-1e9;i<=n;i++){ mx=max(b[i],mx); ans=max(ans,mx-b[i]); } cout<<ans-1; return 0; } -
- 1
信息
- ID
- 7588
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者