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
输出每一阶段的交换次数。
Hint
[数据范围]
70%的数据N<=100
题解
对于每一个点用0和1标记是否排过序
因为每次交换只会置换未排序的项,于是问题就转变成了求向前或向后有多少数字还未排序,也就是1的个数
树状数组可以求区间和,线段树也行
硬是没想到正解,优美的暴力过70分。
代码/pas
var
n:longint;
a,f,t:array[0..100000]of int64;
procedure add(x,y:longint);
begin
while x<=n do
begin
f[x]:=f[x]+y;
x:=x+(x and(-x));
end;
end;
function get(x:longint):longint;
begin
get:=0;
while x>0 do
begin
get:=get+f[x];
x:=x-(x and(-x));
end;
end;
procedure init;
var
i:longint;
begin
readln(n);
for i:=1 to n do
begin
read(a[i]);
t[a[i]]:=i;
add(i,1);
end;
end;
procedure main;
var
i,ans,g:longint;
begin
for i:=1 to n do
begin
ans:=0;
if i mod 2=1 then
begin
g:=(i+1)div 2;
ans:=get(t[g]-1);
add(t[g],-1);
end
else
begin
g:=n-(i-1)div 2;
ans:=get(n)-get(t[g]);
add(t[g],-1);
end;
writeln(ans);
end;
end;
begin
init;
main;
end.