【CF6E Exposition】题解

题目链接

题目

There are several days left before the fiftieth birthday of a famous Berland's writer Berlbury. In this connection the local library decided to make an exposition of the works of this famous science-fiction writer. It was decided as well that it is necessary to include into the exposition only those books that were published during a particular time period. It is obvious that if the books differ much in size, the visitors will not like it. That was why the organizers came to the opinion, that the difference between the highest and the lowest books in the exposition should be not more than \(k\) millimeters.

The library has \(n\) volumes of books by Berlbury, arranged in chronological order of their appearance. The height of each book in millimeters is know, it is \(h_{i}\) . As Berlbury is highly respected in the city, the organizers want to include into the exposition as many books as possible, and to find out what periods of his creative work they will manage to cover. You are asked to help the organizers cope with this hard task.

给一个n个元素的序列,从中挑出最长的子串,要求子串中元素差的最大值不超过k。问有几个最长子串,子串长度,以及这几个子串起始、终止位置。

思路

双指针+单调队列。

首先,这种题,肯定是双指针了,左指针不断往右动,右指针尽量往右跑。

那么如何维护一段区间最大最小值呢?单调队列!

对于每个即将加入的数,看一下和当前区间的最大最小值之差是否小于 \(k\),然后就可以丢进去。

左指针移动时判断队首是否要出队。

总结

感觉这道题如果当时不看标签的话最后应该是打优先队列或RMQ。

一开始以为这道题是求子序列,然后发现题错错了。

其实很多优先队列的题基本上都能用单调队列来优化。

而能用单调队列优化的,双指针是一类很常见的问题。

遇到优先队列或双指针的题,如果不能得到正解,可以考虑双指针。

Code

// Problem: CF6E Exposition
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF6E
// Memory Limit: 62 MB
// Time Limit: 1500 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
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;}
//#define M
//#define mo
#define N 100010
struct node
{
	int x, id; 
}mn[N], mx[N]; 
int n, m, i, j, k; 
int a[N], x, y; 
int topxr, topxl, topyr, topyl; 
int ans, num, l, r; 

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	n=read(); k=read(); 
	for(i=1; i<=n; ++i) a[i]=read(); 
	memset(mn, topxl=topxr=0, sizeof(mn)); 
	memset(mx, topyl=topyr=0, sizeof(mx)); 
	mn[++topxr].x=a[1]; mn[topxr].id=1; 
	mx[++topyr].x=a[1]; mx[topyr].id=1; 
	for(l=r=1; l<=n; ++l)
	{
		if(l-1&&mn[topxl+1].id==l-1) ++topxl; 
		if(l-1&&mx[topyl+1].id==l-1) ++topyl; 
		x=mn[topxl+1].x; y=mx[topyl+1].x;  
		while(r<n && (abs(a[r+1]-x)<=k || topxl==topxr) && (abs(a[r+1]-y)<=k || topyl==topyr))  
		{
			++r; 
			while(topxr>topxl && mn[topxr].x>a[r]) --topxr; 
			mn[++topxr].x=a[r]; mn[topxr].id=r; 
			while(topyr>topyl && mx[topyr].x<a[r]) --topyr; 
			mx[++topyr].x=a[r]; mx[topyr].id=r; 
			x=mn[topxl+1].x; y=mx[topyl+1].x;  
		}
		if(r-l+1>ans) ans=r-l+1, num=0; 
		if(r-l+1==ans) ++num; 
		// printf("%lld %lld\n", topxl, topyl); 
		// printf("> %lld %lld\n", l, r); 
	}
	printf("%lld %lld\n", ans, num); 

	memset(mn, topxl=topxr=0, sizeof(mn)); 
	memset(mx, topyl=topyr=0, sizeof(mx)); 
	mn[++topxr].x=a[1]; mn[topxr].id=1; 
	mx[++topyr].x=a[1]; mx[topyr].id=1; 
	// printf("%lld %lld %lld %lld\n", topxl, topxr, topyl, topyr); 
	for(l=r=1; l<=n; ++l)
	{
		if(l-1&&mn[topxl+1].id==l-1) ++topxl; 
		if(l-1&&mx[topyl+1].id==l-1) ++topyl; 
		x=mn[topxl+1].x; y=mx[topyl+1].x;  
		while(r<n && (abs(a[r+1]-x)<=k || topxl==topxr) && (abs(a[r+1]-y)<=k || topyl==topyr))  
		{
			++r; 
			while(topxr>topxl && mn[topxr].x>a[r]) --topxr; 
			mn[++topxr].x=a[r]; mn[topxr].id=r; 
			while(topyr>topyl && mx[topyr].x<a[r]) --topyr; 
			mx[++topyr].x=a[r]; mx[topyr].id=r; 
			x=mn[topxl+1].x; y=mx[topyl+1].x;  
		}
		if(r-l+1==ans) printf("%lld %lld\n", l, r); 
		// printf("> %lld %lld\n", l, r); 
	}
	return 0; 
}
posted @ 2022-01-13 16:47  zhangtingxi  阅读(72)  评论(0编辑  收藏  举报