单调栈和单调队列专题

单调栈和单调队列专题

简介

内容

通过时间复杂度为O(n)维护静态的区间最值,虽然是静态,但是时间比ST表和线段树更优秀。

实现

顾名思义,单调队列维护一个内部数据为单调的队列。采用合适的方式进行出队和入队操作,让每一个区间的最大、最小值就是队列的头或尾。与一般队列不一样的是,单调队列是一个双向队列,也就是可以在队列的头或尾进行出队入队操作。实现时可以使用数组模拟。

习题

T1 CF940E - Cashback

这个题就是在每次在更新的时候发现取用长度大于c时,就可以看成一个长度为c的区间加上一些单独的区间,一个长度大于2c的区间可以通过变为两个单独的区间实现2更优,需要维护长度为c的最小值即可,采用dp,但是我用了线段树。

Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int n,a[N],dp[N],minn[N<<2],sum[N],c; 
void build(int id,int l,int r){
	if(l==r){
		minn[id]=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	minn[id]=min(minn[id<<1],minn[id<<1|1]);
}
int query(int id,int l,int r,int L,int R){
	if(L<=l&&r<=R)
		return minn[id];
	int mid=(l+r)>>1;
	int res=0x3f3f3f3f;
	if(L<=mid)
		res=min(res,query(id<<1,l,mid,L,R));
	if(R>mid)
		res=min(res,query(id<<1|1,mid+1,r,L,R));
	return res;
}
signed main(){
	//相必是一道dp的题目
	//现在这个块有几个是必不可少的
	//所以这题需要使用滚动数组? 
	cin>>n>>c;
	for(int i=1;i<=n;i++)
		cin>>a[i],sum[i]=sum[i-1]+a[i],dp[i]=sum[i];
	build(1,1,n);
	for(int i=1;i<=n;i++){
		if(i>=c)
			dp[i]=min(dp[i],dp[i-c]+sum[i]-sum[i-c]-query(1,1,n,i-c+1,i));
 		dp[i]=min(dp[i],dp[i-1]+a[i]);
	}
	cout<<dp[n];
}

T2 CF939F - Cutlet

这个题需求在一个区间内反转,首先考虑暴力的dp,两位分别记录正面时间和背面的时间,我们可以通过O(n2)的时间复杂度,算出结果,这时我们发现中间不在区间的部分耗费了大量的时间复杂度,却只是一味的往国家,而且显然O(nk)的时间复杂度可以通过,我们可以考虑一个区间内只能反转最多两次,不然会变得不优,空间的话需要利用滚动数组才行。

Code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,inf=0x3f3f3f3f;
int n,k,f[2][N<<1],que[N<<1];
int main(){
	//这个题的问题就在于如何评判这个是否
	//所以考虑dp,用滚动数组 
	cin>>n>>k;
	for(int i=1;i<n*2;i++)
		f[0][i]=inf;
	for(int i=1,l,r;i<=k;i++){
		cin>>l>>r;
		for(int j=0;j<=n;j++)
			f[i&1][j]=f[!(i&1)][j];
		int h=1,t=0;
		for(int j=r;j>=0;j--){
			while(h<=t&&que[h]<l-j)
				h++;
			while(h<=t&&f[!(i&1)][que[t]]>f[!(i&1)][r-j])
				t--;
			que[++t]=r-j;
			f[i&1][j]=min(f[!(i&1)][j],f[!(i&1)][que[h]]+1);
		}
		h=1,t=0;
		for(int j=0;j<=min(n,r);j++){
			while(h<=t&&que[h]<j-r+l)
				h++;
			while(h<=t&&f[!(i&1)][que[t]]>f[!(i&1)][j])
				t--;
			que[++t]=j;
			f[i&1][j]=min(f[i&1][j],f[!(i&1)][que[h]]+2);
		}
	}
	if(f[k&1][n]==inf)
		cout<<"Hungry\n";
	else
		cout<<"Full\n"<<f[k&1][n];	
	return 0;
	//7.12
} 

T3 CF1582G Kuzya and Homework

posted @   Dengyouk  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示