poj2182

首先容易知道,最后一个数是最容易确定的,于是从后往前确定

对于位置j,它的数就是1~n中剩余数的第a[j]+1小的数

这当然可以用平衡数做,复杂度为O(nlogn)

有没有更简洁得算法?树状数组+二分

 1 var v:array[0..8010] of boolean;
 2     c,ans,a:array[0..8010] of longint;
 3     i,j,n:longint;
 4 function lowbit(x:longint):longint;
 5   begin
 6     exit(x and (-x));
 7   end;
 8 
 9 function sum(x:longint):longint;
10   begin
11     sum:=0;
12     while x>0 do
13     begin
14       sum:=sum+c[x];
15       x:=x-lowbit(x);
16     end;
17   end;
18 
19 function kth(t:longint):longint;
20   var l,r,m,p:longint;
21   begin
22     l:=1;
23     r:=n;
24     while l<=r do
25     begin
26       m:=(l+r) shr 1;
27       p:=sum(m);       //统计二分得到的这个数前面有几个比它小的
28       if (p=t) and not v[m] then exit(m);   //注意不要忘记判断这个数是否存在
29       if p<t then l:=m+1 else r:=m-1;
30     end;
31   end;
32 
33 procedure add(x,w:longint);
34   begin
35     while x<=n do
36     begin
37       c[x]:=c[x]+w;
38       x:=x+lowbit(x);
39     end;
40   end;
41 
42 begin
43   readln(n);
44   for i:=2 to n do
45     readln(a[i]);
46   for i:=1 to n do    //初始化
47     add(i,1);
48   fillchar(v,sizeof(v),false);
49   for i:=n downto 1 do
50   begin
51     ans[i]:=kth(a[i]+1);  //确定当前位置
52     v[ans[i]]:=true;      //删除这个数
53     add(ans[i],-1);
54   end;
55   for i:=1 to n do
56     writeln(ans[i]);
57 end.
View Code

总的复杂度为O(n*logn*logn)虽然慢了一点,但是编程复杂度大大下降

原文地址:https://www.cnblogs.com/phile/p/4473281.html