【单调队列】【120715测试】【朱全明NOIP模拟题】Window

 样例
window.in
  8 3
  1 3 -1 -3 5 3 6 7
window.out
  -1 -3 -3 -3 3 3
  3 3 5 5 6 7

前面已经说了朴素能得30分,加上优化后能得100分

这里说说单调队列http://www.cnblogs.com/oijzh/articles/2647166.html

利用单调队列的单调性,每次入队,算最小的时候,只要当前最小的没出队,那么其他比它大的就根本不可能作为最小的输出,所以每次入队判断即可

算最大的同理

如果大家对单调队列理解不是很清楚,可以看看资料,或者看看代码,是这理解一下

单调队列 Pascal Code

program window;

var
  n,k:longint;
  a:array[0..1000000+10] of longint;
  l,r:longint;
  q:array[0..1000000+10] of longint;

procedure init;
begin
  assign(input,'window.in');
  assign(output,'window.out');
  reset(input);
  rewrite(output);
end;
procedure outit;
begin
  close(input);
  close(output);
  halt;
end;

procedure readdata;
var
  i:longint;
begin
  read(n,k);
  for i:=1 to n do read(a[i]);
end;

procedure main;
var
  i:longint;
begin
  fillchar(q,sizeof(q),0);l:=0;r:=0;
  for i:=1 to n do
  begin
    if q[l+1]<i-k+1 then inc(l);
    while (l<r)and(a[q[r]]>=a[i]) do dec(r);
    inc(r);
    q[r]:=i;
    if i>=k then write(a[q[l+1]],' ');
  end;
  writeln;
  fillchar(q,sizeof(q),0);l:=0;r:=0;
  for i:=1 to n do
  begin
    if q[l+1]<i-k+1 then inc(l);
    while (l<r)and(a[q[r]]<=a[i]) do dec(r);
    inc(r);
    q[r]:=i;
    if i>=k then write(a[q[l+1]],' ');
  end;
end;

begin
  init;
  readdata;
  main;
  outit;
end.

 

 

 

附上快排优化的思路和代码

先把数据快排一次,注意要处理处一个标号数组一起快排!!!

然后n个数,每个区间k个数,那么就会有n-k+1个区间,分别用1..n-k+1表示

求最小的时候,把队列从最小开始扫描一次,比如最小是-3 标号是2 ,那么就从2开始把往前的k个区间都填成-3,(注意:要先判断该区间是否填过,填过的不能再填,因为后面的不可能比前面的更优!!!判断可以用hash数组实现),在用一个计数器count,每填一个就+1,直到count=n-k+1的时候表示全部区间填完了,就马上退出当前这个计算模块。然后计算最大的同。

Pascal Code

program window;

var
  n,k:longint;
  a,nn,min,max:array[0..1000000+10] of longint;
  h:array[0..1000000+10] of boolean;
  num,maxnum:longint;

procedure init;
begin
  assign(input,'window.in');
  assign(output,'window.out');
  reset(input);
  rewrite(output);
end;
procedure outit;
begin
  close(input);
  close(output);
  halt;
end;

procedure readdata;
var
  i:longint;
begin
  read(n,k);
  for i:=1 to n do read(a[i]);
  for i:=1 to n do nn[i]:=i;
end;

procedure qs(l,r:longint);
var
  i,j,x,t:longint;
begin
  i:=l;j:=r;x:=a[i+(j-i)div 2];
  repeat
    while a[i]>x do inc(i);
    while a[j]<x do dec(j);
    if i<=j then
    begin
      t:=a[i];a[i]:=a[j];a[j]:=t;
      t:=nn[i];nn[i]:=nn[j];nn[j]:=t;
      inc(i);dec(j);
    end;
  until i>j;
  if i<r then qs(i,r);
  if l<j then qs(l,j);
end;

procedure workmax;
var
  i,j,t:longint;
begin
  fillchar(h,sizeof(h),0);
  maxnum:=n-k+1;
  num:=0;
  for i:=1 to n do
  begin
    t:=nn[i];
    for j:=1 to k do
    begin
      if (t<1) then continue;
      if (not h[t])and(t<=maxnum) then
      begin
        h[t]:=true;
        max[t]:=a[i];
        inc(num);
        if num=maxnum then exit;
      end;
      dec(t);
    end;
  end;
end;

procedure workmin;
var
  i,j,t:longint;
begin
  fillchar(h,sizeof(h),0);
  maxnum:=n-k+1;
  num:=0;
  for i:=n downto 1 do
  begin
    t:=nn[i];
    for j:=1 to k do
    begin
      if t<1 then continue;
      if (not h[t])and(t<=maxnum) then
      begin
        h[t]:=true;
        min[t]:=a[i];
        inc(num);
        if num=maxnum then exit;
      end;
      dec(t);
    end;
  end;
end;

procedure main;
var
  i,j,t:longint;
begin
  qs(1,n);
  //for i:=1 to n do write(a[i],' ');
  //找最大
  workmax;
  //找最小
  workmin;
  for i:=1 to n-k+1 do write(min[i],' ');writeln;
  for i:=1 to n-k+1 do write(max[i],' ');writeln;
end;

begin
  init;
  readdata;
  main;
  outit;
end.

 

posted @ 2012-08-20 10:13  jiangzh  阅读(227)  评论(0编辑  收藏  举报