poj2823

题意:给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数。

分析:在这里我们以求最大值为例,最小值同理。用单调双向队列来做,动态规划。从左到右把窗户推一便,每推一格,就把新来的元素入队,入队过程中先把队尾小于它的元素全去掉(因为这些值不可能成为窗子区间内的最大值了),再把它加到队尾。这样就保证了队列中元素是单调递减的。还要注意及时把不在窗户区间内的队首元素弹出。每次要取窗子区间内的最大值,只需看队首元素即可。

View Code
#include <iostream>
#include
<cstdlib>
#include
<cstring>
#include
<cstdio>
usingnamespace std;

#define maxn 1000005

struct Item
{
int value, index;
} q[maxn], f[maxn];

int n, k, head, tail;

void ins1(Item &a)
{
while (head != tail && q[tail -1].value >= a.value)
{
tail
--;
if (tail <0)
tail
+= maxn;
}
q[tail
++] = a;
if (tail >= maxn)
tail
=0;
if (a.index - q[head].index >= k)
head
++;
if (head >= maxn)
head
=0;
}

void ins2(Item &a)
{
while (head != tail && q[tail -1].value <= a.value)
{
tail
--;
if (tail <0)
tail
+= maxn;
}
q[tail
++] = a;
if (tail >= maxn)
tail
=0;
if (a.index - q[head].index >= k)
head
++;
if (head >= maxn)
head
=0;
}


int main()
{
//freopen("D:\\t.txt", "r", stdin);
scanf("%d%d", &n, &k);
for (int i =0; i < n; i++)
{
scanf(
"%d", &f[i].value);
f[i].index
= i;
}
for (int i =0; i < k -1; i++)
ins1(f[i]);
for (int i = k -1; i < n; i++)
{
ins1(f[i]);
printf(
"%d", q[head].value);
if (i != n -1)
printf(
"");
}
printf(
"\n");
head
=0;
tail
=0;
for (int i =0; i < k -1; i++)
ins2(f[i]);
for (int i = k -1; i < n; i++)
{
ins2(f[i]);
printf(
"%d", q[head].value);
if (i != n -1)
printf(
"");
}
return0;
}
posted @ 2011-03-20 14:40  金海峰  阅读(231)  评论(0编辑  收藏  举报