P10878 [JRKSJ R9] 在相思树下 III 题解
Description
给定一个长为 的序列 ,需要对它进行两种操作共 次。
对一个长度为 的序列 进行一次操作将会把序列变为一个长为 的序列 :
- 操作一中,;
- 操作二中,。
给定整数 ,你只能进行至多 次操作一。进行 次操作后序列 的长度变为 。你可以任意安排操作的顺序,求最终剩余的数 的最大值。
Solution
比第一题简单。
两个关键性质就是操作一做满 次最优,且做完操作一再做操作二。
我们发现操作一每次一定会把当前最小值消去,使最大值数量变多,操作二一定会把当前最大值消去,使最小值数量变多。
先做操作一则能抬高数值下限,做满 次使最小值最大,最大值数量最多,此种决策最优。
而在一次操作一前做操作二,不仅会使最小值变多,还会降低数值上限,不优于上种决策。
确定了操作顺序后就完了吗?并不是,还需要找到最小值,而直接模拟是 的。
发现在一次操作一后可能不止最小值会消去,如 做一次操作一变成 。
又发现一个数会被左右两边第一个比它大的数 消去,会在 次操作一后消失。
然后在在所有不能在 次操作一之内消去的数中取最小值即可。
用单调栈找 可 做完。
Code
#include<bits/stdc++.h>
using namespace std;
int n,m;
int a[1000010];
int l[1000010],r[1000010];
stack<int> s;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
while(s.size()&&a[s.top()]<=a[i]){
s.pop();
}
l[i]=s.size()?s.top():0;
s.push(i);
}
while(s.size()) s.pop();
for(int i=n;i>=1;i--){
while(s.size()&&a[s.top()]<=a[i]){
s.pop();
}
r[i]=s.size()?s.top():n+1;
s.push(i);
}
int minn=1e9;
for(int i=1;i<=n;i++){
if(r[i]-1-l[i]>m){
minn=min(minn,a[i]);
}
}
cout<<minn;
return 0;
}
本文作者:larryyu_blog
本文链接:https://www.cnblogs.com/larryyu/p/18393536
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步