当前位置:网站首页>单调栈一些题目练习
单调栈一些题目练习
2022-08-04 10:55:00 【minato_yukina】
最近发现单调栈不怎么会熟练使用,写点东西提醒下自己
第一题
给你一个数组 a i a_i ai,问你对于一个长度为 i i i的连续区间,最大化该区间的最小值。你需要回答长度1~n的区间的答案并且输出他们。
对于这个问题,其实我已经遇过好几次了,这类问题需要关注的是谁作为最小值而造成的区间影响.
我们认为 a i ai ai就是当前区间的最小值,那么我们需要处理出当前该元素的最左边索引 l l l,最右索引 r r r,那么它就可以作为答案算入区间 r − l + 1 中 r-l+1中 r−l+1中.
对于处理出 l , r l,r l,r这两个值,这就是单调栈的作用了。
首先处理r数组,从前往后扫,如果碰到一个值 a i ai ai大于栈顶元素,取出栈顶所有元素,把他们的值 r [ j ] = i r[j]=i r[j]=i
再处理 l l l数组,从后边往前边扫,如果碰到一个元素大于当前 i i i,和 r r r一样的处理
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
int a[maxn];int s[maxn];
int l[maxn],r[maxn],ans[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int top = 0;
for(int i=1;i<=n;i++){
while(top>0&&a[s[top]]>a[i]){
r[s[top]] =i-1;top--;
}
top++;
s[top] = i;
}
while(top>0) r[s[top]] = n,top--;
for(int i=n;i>=1;i--){
while(top>0&&a[s[top]]>a[i]){
l[s[top]] = i+1;top--;
}
top++;s[top]=i;
}
while(top>0) l[s[top]]=1,top--;
for(int i=1;i<=n;i++){
int len = r[i]-l[i]+1;
ans[len] = max(ans[len],a[i]);
}
// for(int i=1;i<=n;i++){
// cout<<i<<" "<<l[i]<<" "<<r[i]<<"\n";
// }
for(int i=n-1;i>=1;i--){
ans[i] = max(ans[i+1],ans[i]);
}
for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
}
第二题
与上题类似地,使用单调栈来分别处理第i个牛是否有那样的点x,
x . h > 2 ∗ a i . h , a b s ( x . x − a i . x ) < = d x.h>2*a_i.h,abs(x.x-a_i.x)<=d x.h>2∗ai.h,abs(x.x−ai.x)<=d.
我们使用一个单调队列维护队列中的h元素单调下降性,当前元素的 h h h大于队尾元素时,不断地弹出队尾.
当距离不满足要求时,不断弹出队首,这样剩下的元素就是最可能合法地与i匹配的牛,这个元素显然就是队首,因为它的h元素值最大,而且位置也符合要求,其他元素不可能比它更适合.
对于左边的情况我们正序扫描一遍,右边的情况倒序扫描一遍即可.
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];
struct Node{
int x,h;
bool operator <(const Node&rhs)const{
return x<rhs.x;
}
}a[maxn];
int que[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,d;cin>>n>>d;
for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].h;
sort(a+1,a+1+n);
deque<int> dq;
vector<bool> left(n+1,false),right(n+1,false);
for(int i=1;i<=n;i++){
while(!dq.empty()&&a[dq.back()].h<a[i].h) dq.pop_back();
while(!dq.empty()&&abs(a[i].x-a[dq.front()].x)>d) dq.pop_front();
if(!dq.empty()&&a[dq.front()].h>=2*a[i].h) left[i] = true;
dq.push_back(i);
}
while(!dq.empty()) dq.pop_front();
for(int i=n;i>=1;i--){
while(!dq.empty()&&a[dq.back()].h<a[i].h) dq.pop_back();
while(!dq.empty()&&abs(a[i].x-a[dq.front()].x)>d) dq.pop_front();
if(!dq.empty()&&a[dq.front()].h>=2*a[i].h) right[i] = true;
dq.push_back(i);
}
// for(int i=1;i<=n;i++){
// cout<<a[i].x<<" "<<a[i].h<<" ";
// }
// cout<<"\n";
// for(int i=1;i<=n;i++) cout<<left[i]<<" ";
// cout<<"\n";
// for(int i=1;i<=n;i++) cout<<right[i]<<" ";
// cout<<"\n";
int ans=0;
for(int i=1;i<=n;i++){
if(left[i]&&right[i]) ans++;
}
cout<<ans<<"\n";
}
第三题
仍然是一个比较明显的单调队列,如果我们断环为链,发现不成立的标准就是对于一个位置 i i i,有 s u m j − s u m i < 0 ( j > = i & & j < = i + n − 1 ) sum_j-sum_i<0(j>=i\&\&j<=i+n-1) sumj−sumi<0(j>=i&&j<=i+n−1).那么我们发现只要选取区间 [ i + 1 , i + n − 1 ] 中的最小的 s u m j 即可 , 使用单调队列维护这段最小值就能算出答案 [i+1,i+n-1]中的最小的sum_j即可,使用单调队列维护这段最小值就能算出答案 [i+1,i+n−1]中的最小的sumj即可,使用单调队列维护这段最小值就能算出答案.
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6+5;
const int INF = 1e9+7;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) (a).begin(), (a).end()
#define pb(a) push_back(a)
vector<int> G[maxn];ll a[maxn],sum[maxn];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++) a[i+n] = a[i];
for(int i=1;i<=2*n;i++) sum[i] = sum[i-1]+a[i];
deque<int> dq;ll ans = 0;
for(int i=2*n;i>=1;i--){
while(!dq.empty()&&dq.front()-i>n) dq.pop_front();
if(i<=n&&!dq.empty()&&sum[dq.front()]-sum[i]>=0) ans++;
while(!dq.empty()&&sum[dq.front()]>=sum[i]) dq.pop_back();
dq.push_back(i);
}
cout<<ans<<"\n";
}
边栏推荐
猜你喜欢
随机推荐
Graphical Hands-on Tutorial--ESP32 OTA Over-the-Air Upgrade (VSCODE+IDF)
标准C语言学习总结12
Use pytest hook function to realize automatic test result push enterprise WeChat
[easyUI]修改datagrid表格中的值
【LeetCode】701.二叉搜索树中的插入操作
Maple 2022软件安装包下载及安装教程
Mysql高级篇学习总结14:子查询优化、排序优化、GROUP BY优化、分页查询优化
onlyoffice设置跟踪变化trackChanges默认为对自己启动
Camunda overall architecture and related concepts
Mobile open source low code tools beeware and kivy
datax oracle to oracle增量同步
数据化管理洞悉零售及电子商务运营——零售密码
昨夜梦佳人,七夕试伊妆丨基于ModelArts实现AI妆容迁移丨【玩转华为云】
Oracle中对临时表空间执行shrink操作
JUC (1) threads and processes, concurrency and parallelism, thread state, locks, producers and consumers
MySQL核心SQL:结构化查询语句SQL、库操作、表操作、CRUD
mae,mse,rmse分别利用sklearn和numpy实现
JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
MySQL core SQL: SQL structured query statements, library, table operation, CRUD
123