Lost Cows
-
題意
FJ有n頭牛,編號 1~n ,但是這些牛並沒有按照編號排隊,但是 FJ 知道每頭牛前面有幾頭編號比這頭牛編號小,現在問你每頭牛的編號。 -
題解
從最後一頭牛開始,其它牛都已經在隊列裏,假如這頭牛前面有 x 頭牛編號比它小,那麼這頭牛就是編號第 x 小(按編號從小到大排序)的牛的編號加一。知道了這頭牛的編號,就可以把這頭牛從隊列中趕走了,因爲有沒有它都不會影響到前邊的牛。這樣,第 n-1 頭牛就成了最後一頭牛,再重複上面的過程就可以了。
至於解法,可以用暴力解法,每次數 x+1 次,但是複雜度很高,稍有不慎就會超時,但是思路是正確的,只需要降低算法的複雜度就可以了,因爲是找第 x+1 頭牛的編號,相當於求前綴和,很容易想到的就是樹狀數組和線段樹。相比線段樹,樹狀數組的代碼更簡潔,因爲只涉及區間求和,所以推薦使用樹狀數組。
還有,樹狀數組在求區間和的時候使用二分法可以進一步優化。 -
AC代碼
樹狀數組#include<iostream> #include<cstdio> using namespace std; #define lowbit(x) ((x) & (-x)) const int MAX = 10000; int tree[MAX], pre[MAX], ans[MAX]; int n; void add(int x, int d){ while(x<=n){ tree[x] += d; x += lowbit(x); } } int sum(int x){ int sum = 0; while(x>0){ sum += tree[x]; x -= lowbit(x); } return sum; } int findpos(int x){ int l=1, r=n; while(l<r){ int mid = (l+r)>>1; if(sum(mid)<x) l = mid+1; else r = mid; } return l; } int main(){ scanf("%d", &n); pre[1] = 0; for(int i=2; i<=n; i++) scanf("%d", &pre[i]); for(int i=1; i<=n; i++) tree[i] = lowbit(i); for(int i=n; i>0; i--){ ans[i] = findpos(pre[i]+1); add(ans[i], -1); } for(int i=1; i<=n; i++) printf("%d\n", ans[i]); return 0; }
線段樹#include<iostream> #include<stdio.h> #include<cmath> using namespace std; const int MAX = 10000; int pre[MAX], tree[4*MAX], ans[MAX]; void BuildTree(int n, int last_left){ int i; for(i=last_left; i<last_left+n; i++){ tree[i] = 1; } while(last_left != 1){ for(i=last_left/2; i<last_left; i++){ tree[i] = tree[2*i] + tree[2*i+1]; } last_left = last_left/2; } } int query(int u, int num, int last_left){ tree[u]--; if(tree[u]==0 && u>=last_left){ return u; } if(tree[u<<1]<num) return query((u<<1)+1, num-tree[u<<1], last_left); else return query(u<<1, num, last_left); } int main(){ int n, last_left, i; scanf("%d", &n); pre[1] = 0; last_left = 1<<(int(log(n)/log(2))+1); for(i=2; i<=n; i++) scanf("%d", &pre[i]); BuildTree(n, last_left); for(i=n; i>=1; i--) ans[i] = query(1, pre[i]+1, last_left) - last_left + 1; for(i=1; i<=n; i++) printf("%d\n", ans[i]); return 0; }