排序 纪中 1386 树状数组/玄学

Description

  你收到一项对数组进行排序的任务,数组中是1到N个一个排列。你突然想出以下一种特别的排序方法,分为以下N个阶段:
  •阶段1,把数字1通过每次交换相邻两个数移到位置1;
  •阶段2,用同样的方法把N移到位置N;
  •阶段3,把数字2移到位置2处;
  •阶段4,把数字N-1移到位置N-1处;
  •依此类推。
  换句话说,如果当前阶段为奇数,则把最小的未操作的数移到正确位置上,如果阶段为偶数,则把最大的未操作的数移到正确位置上。
  写一个程序,给出初始的排列情况,计算每一阶段交换的次数。

Input

  第一行包含一个整数N(1<=N<=100000),表示数组中元素的个数。
  接下来N行每行一个整数描述初始的排列情况。

Output

  输出每一阶段的交换次数。

分析

对于每一个点用0和1标记是否排过序

因为每次交换只会置换未排序的项,于是问题就转变成了求向前或向后有多少数字还未排序,也就是1的个数

树状数组可以求区间和,线段树也行

硬是没想到正解,优美的暴力过70分。
载自olahiuj

代码

var
  b:array[1..100010] of longint;
  a:array[1..100010] of longint;
  i,j,k:longint;
  l,r:longint;
  n,m:longint;

procedure bian(p,c:longint);
begin
  while p<=m do
    begin
      b[p]:=b[p]+c;
      p:=p+(p and (p xor (p-1)));
    end;
end;

function tong(p:longint):longint;
begin
  tong:=0;
  while p>0 do
    begin
      tong:=tong+b[p];
      p:=p-(p and (p xor (p-1)));
    end;
end;

begin
  readln(n);
  m:=n;
  for i:=1 to n do
    begin
      readln(j);
      a[j]:=i;
    end;
  for i:=1 to n do
    bian(i,1);
  l:=0; r:=n+1;
  for i:=1 to n do
    case i mod 2 of
      1:begin
          writeln(tong(a[(i+1) div 2])-1);
          bian(a[(i+1) div 2],-1);
        end;
      0:begin
          writeln(tong(n)-tong(a[n-(i-1) div 2]));
          bian(a[n-(i-1) div 2],-1);
        end;
    end;
end.
posted @ 2016-07-12 22:00  一个响亮的蒟蒻  阅读(169)  评论(0编辑  收藏  举报