首先容易知道,最后一个数是最容易确定的,于是从后往前确定
对于位置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.
总的复杂度为O(n*logn*logn)虽然慢了一点,但是编程复杂度大大下降