您的位置:首页 > 其它

POJ 2823 Sliding Window

2011-06-22 14:45 211 查看
这是一道最最基础的使用双端队列优化的题目。题目的意思就是求出指定长度子序列的最大值和最小值。

如果说硬要弄一个方程的话,那就是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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: