HDU 5592 ZYB's Game 【樹狀數組】+【二分】
阿新 • • 發佈:2018-12-15
ons get 宋體 pre 逆序 blank binary tps 二分查找
<題目鏈接>
題目大意:
給你一個由1~n,n個數組成的序列,給出他們每個的前綴逆序數,現在要求輸出這個序列。
解題分析:
由前綴逆序數很容易能夠得到每個數的逆序數。假設當前數是i,它前面比它小的數為a[i]( i - 1 - i的逆序數即可),我們不難知道,i在前i個數中是第i+1大的。然後我們從後往前考慮,每次都能確定一個位置的數的大小,根據當前位置i的數在 1~i 的數的大小,我們用二分查找快速聰當前還未分配的數中給它分配相應大小的數值,然後將這個數值從可分配的數中剔除,防止對前面的數造成影響(相當於每次只考慮i前面的數,i後面的數都已經確定好了數值)。
1 #include <cstdio> 2#include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int N = 5e4+5; 6 int n; 7 int a[N],tr[N],ans[N]; 8 inline int lowbit(int x){return x&(-x);} 9 void add(int x,int val){ 10 for(int i=x;i<=N;i+=lowbit(i)) 11 tr[i]+=val; 12 } 13 intsum(int x){ 14 int ans=0; 15 for(int i=x;i>0;i-=lowbit(i)) 16 ans+=tr[i]; 17 return ans; 18 } 19 int Binary(int k){ 20 int lt = 1, rt = n, mid, t; 21 while (lt+1 < rt){ 22 mid = (lt+rt)>>1; 23 t = sum(mid); 24 if (t >= k) rt = mid;25 else lt = mid; 26 } 27 if (sum(lt) == k) return lt; 28 else return rt; 29 } 30 void solve(){ 31 for(int i=1;i<=n;i++)add(i,1); 32 for(int i=n;i>0;i--){ //從後往前,逐漸分配可供選擇的數 33 ans[i]=Binary(a[i]+1); //在當前可供選擇的數中,挑選第a[i]+1大的數 34 add(ans[i],-1); //因為是根據第i個數是前i個數中第a[i]+1大的來確定位置的,所以要消除i後面的所有元素的影響 35 } 36 for(int i=1;i<=n;i++) 37 printf("%d%s",ans[i],i==n?"\n":" "); 38 } 39 int main(){ 40 int T;scanf("%d",&T);while(T--){ 41 scanf("%d",&n); 42 int pre=0, now; 43 for(int i=1;i<=n;i++){ 44 scanf("%d",&now); 45 a[i]=i-1-(now-pre); 46 pre=now; 47 } 48 memset(tr,0,sizeof(tr)); 49 solve(); 50 } 51 }
2018-12-15
HDU 5592 ZYB's Game 【樹狀數組】+【二分】