YY_More

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

这是一道最最基础的使用双端队列优化的题目。题目的意思就是求出指定长度子序列的最大值和最小值。

如果说硬要弄一个方程的话,那就是f[i]=max/min(a[j]) (f[i]指以i结尾的子序列,a[j]指原序列中第k个元素。i-k+1<=j<=i)

显然我们可以通过单调队列来维护最大值和最小值,复杂度O(n)

按理说双端队列应该有两个域,一个存下标,一个存关键值,但是这道题中关键值很容易从原序列中取出,所以就省掉了这个域,在这里提醒一下刚接触单调队列的人。

当然,这个数据范围暴力RMQ也可以过,其实也不是很暴力啦,但是跟O(n)的算法比就不太优美了。

提示:在POJ上做这道题的时候,如果你超时了,或者几千ms水过,建议你在两个方面进行改进。

第一,不要使用STL。事实上,由于自身容器类型的限制,deque在时间空间上都是非常不适用于OI题目的。而自己写队列速度快,空间小,而且代码也短。

第二,参考一下我的代码中读入输出的部分(这个就是所谓蛋疼IO优化)。POJ上很多题目卡scanf和printf,在G++下光读入都可能会超时。遇到这种情况换C++编译好了。

//By YY_More
#include<cstdio>
char c;
int i,n,k,f[1000050],L,R,H,x,D[1000050];
inline int getmin(){
	while (D[L]<=i-k) L++;
	return f[D[L]];
};	
inline void insertmin(){
	while (L<=R&&f[D[R]]>=f[i]) R--;
	D[++R]=i;
};	
inline int getmax(){
	while (D[L]<=i-k) L++;
	return f[D[L]];
};	
inline void insertmax(){
	while (L<=R&&f[D[R]]<=f[i]) R--;
	D[++R]=i;
};	
inline void put(int x){
	if(x< 0){
		putchar('-');
		x = -x;
	}
	if(x == 0){
		putchar('0');
		return;
	}
	char s[20];
	int bas = 0;
	for(;x;x/=10)s[bas++] = x%10+'0';
	for(;bas--;)putchar(s[bas]);
	return;
}
int main(){
	while (true){
		c=getchar();
		if (c==' ') break;
		n=n*10+c-48;	
	}
	while (true){
		c=getchar();
		if (c=='\n') break;
		k=k*10+c-48;	
	}
	int y=1;
	while (true){
		c=getchar();
		if (c=='\n') {f[++H]=x*y;break;}
		if (c==' ') {f[++H]=x*y;y=1;x=0;};
		if (c=='-') y=-1;
		if (c>='0'&&c<='9') x=x*10+c-48;
	}	
	L=0;R=-1;
	for (i=1;i<=n;i++){
		insertmin();
		if (i>=k) {
			put(getmin());
			if (i<n) putchar(' ');
			}
		}	
	putchar('\n');
	L=0;R=-1;
	for (i=1;i<=n;i++){
		insertmax();
		if (i>=k) {
			put(getmax());
			if (i<n) putchar(' ');
			}
		}
	putchar('\n');
	return 0;
}
posted on 2011-06-22 14:45  YY_More  阅读(1010)  评论(0编辑  收藏  举报