Educational Codeforces Round 65 (Rated for Div. 2) E. Range Deleting 二分 or 双指针

本文详细解析了一道关于数组单调性的算法题目,通过预处理数组元素的首次和末次出现位置,采用从大到小及从小到大的双方向讨论策略,结合二分查找或移动指针技巧,高效解决了寻找特定子数组的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接
题意:给你一个数组,让你求出满足删除 ( l , r ) (l,r) (l,r)内所有值后,剩下的数组单调不减的 ( l , r ) , l ≤ r (l,r),l \leq r (l,r),lr的对数。
思路:首先,对每个数进行预处理最先出现和最后出现的位置,若数组没这个数,则最后出现的位置设置成一个极大数,最先出现为0.
然后从大到小进行讨论,看不删这个数是否合法。意为:假设最大数为 q q q,那么如果当前数为 t t t,是否满足 t − q t-q tq所有数出现的位置均满足单调不减。满足既可以不删。然后用数组记录到 t t t的最左边的坐标,不满足的话那么这个数必须删,也就是右指针的初始值。
然后从小到大进行累加贡献。先讨论不删这个数是否合法(同上),若不合法的话,则这个数必须删,后面也就不用讨论了。然后每次二分或者移动右指针进行讨论,设当前右指针为 r r r,即要满足 l r i g h t ≤ r l e f t l_{right}\leq r_{left}% lrightrleft,不满足的话右指针往右移动即可。每次记录当前出现的最右的位置即可。
细节见代码

#include<bits/stdc++.h>

#define LL long long
#define fi first
#define se second
#define mp make_pair
#define pb push_back

using namespace std;

LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
LL powmod(LL a,LL b,LL MOD){LL ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
const int N = 1e6 +11;
int n,x,a[N],l[N],r[N];
int b[N],c[N],R,dy,L;
int main(){
	ios::sync_with_stdio(false);
	cin>>n>>x;
	for(int i=1;i<=x;i++)l[i]=n+33;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		r[a[i]]=i;
		if(l[a[i]]==n+33)l[a[i]]=i;
	}	
	LL ans=0;
	L=n+33;
	b[x+1]=n+34;
	for(int i=x;i>=1;i--){
		int sta=0;
		if(r[i]>L){sta=1;}
		b[i]=min(b[i+1],l[i]);
		if(sta){dy=i;break;}
		L=min(L,l[i]);
	}
	for(int i=1;i<=x;i++){
		int sta=0;
		if(l[i]<R)sta=1;
		dy=max(dy,i);
		int dx=dy,y=x,k=x+1;
		while(dy<=x&&b[dy+1]<=R)dy++;
		ans+=x-dy+1;
		if(sta)break;
		R=max(R,r[i]);
	}
	cout<<ans<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值