poj2823

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

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

View Code
#include < iostream >
#include
< cstdlib >
#include
< cstring >
#include
< cstdio >
using namespace 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(
" " );
}
return 0 ;
}

你可能感兴趣的:(poj)