这道题还是很经典的
给出了一个序列,代表的是比该位置的牛靠前站的且序号比他小的牛的个数
然后思想类似于2828,正序看的话,看不出有什么规律,但是逆序的话,就能看出当前序列的最后一头牛的编号是可以确定的,就相当于有一个队列,初始化全为1,有牛占了就把相应位置变为0,然后我们只管那些位置为1的地方,往里一头一头的塞牛,塞一头,能塞的地方就少一个,但是和之前塞过的就没关系了,这也符合题目中,只管比该位置靠前的且序号小的 这个条件
/* ID: sdj22251 PROG: inflate LANG: C++ */ #include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cmath> #include <ctime> #define MAXN 10000 #define INF 1000000000 #define eps 1e-7 #define PI 3.1415926535898 #define L(x) x<<1 #define R(x) x<<1|1 using namespace std; struct node { int left, right, mid; int cnt; }tree[4 * MAXN]; int a[MAXN], ans[MAXN]; void make_tree(int s, int e, int C) { tree[C].left = s; tree[C].right = e; tree[C].mid = (s + e) >> 1; tree[C].cnt = tree[C].right - tree[C].left + 1; if(s == e) return; make_tree(s, tree[C].mid, L(C)); make_tree(tree[C].mid + 1, e, R(C)); } void insert(int p, int x, int C) { tree[C].cnt--; if(tree[C].left == tree[C].right) { ans[x] = tree[C].left; return; } if(tree[L(C)].cnt > p) insert(p, x, L(C)); else insert(p - tree[L(C)].cnt, x, R(C)); } int main() { int n; scanf("%d", &n); make_tree(1, n, 1); for(int i = 2; i <= n; i++) scanf("%d", &a[i]); for(int i = n; i >= 1; i--) insert(a[i], i, 1); for(int i = 1; i <= n; i++) printf("%d\n", ans[i]); return 0; }
下面是树状数组做法
其实还是那个原理 ,倒序推。刚开始的时候把n个位置都准备好,然后塞牛,塞一头就把相关的位置删1,表示之前能站的地方少了一个。
然后倒序找位置的时候,用的是二分查找。因为树状数组的和,也是有序的
/* ID: sdj22251 PROG: inflate LANG: C++ */ #include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cmath> #include <ctime> #define MAXN 10000 #define INF 1000000000 using namespace std; int a[MAXN]; int ans[MAXN]; int t[MAXN], n; int lowbit(int x) { return x & -x; } void modify(int x, int v) { for(int i = x; i <= n; i += lowbit(i)) a[i] += v; } int getsum(int x) { int sum = 0; for(int i = x; i > 0; i -= lowbit(i)) sum += a[i]; return sum; } int search(int x) { int low = 1; int high = n; int mid; while(low <= high) { mid = (low + high) >> 1; int tmp = getsum(mid); if(x <= tmp) high = mid - 1; else low = mid + 1; } return low; } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) modify(i, 1);//把这些位置准备好,表示都可以站牛 for(int i = 2; i <= n; i++) scanf("%d", &t[i]); for(int i = n; i >= 1; i--) { ans[i] = search(t[i] + 1); modify(ans[i], -1); //这头牛占了一个位置,把之后有关系的地方都删掉这个1 } for(int i = 1; i <= n; i++) printf("%d\n", ans[i]); return 0; }