244. 谜一样的牛
题解参考AcWing 244. 谜一样的牛 - AcWing
另外,起初我以为是要对身高数组直接建立树状数组来求解问题,但是这样做的信息太少,根本不能得到答案;
实际上,树状数组是用来辅助我们求身高的,我们需要构造一个树状数组,来帮助我们确认牛的身高。
很多数据结构类的问题也是这样,不直接对所求问题建立数据结构,而是利用某些特殊的已知信息来建立数据结构,帮助我们求解问题。
1.二分
#include <iostream> #include <stdio.h> #include <algorithm> #include <string> #define For(i, j, n) for(int i = j ; i <= n ; ++i) using namespace std; const int N = 1e5 + 5; int lowbit(int x) { return x & (-x); } int n, a[N], tr[N], h[N]; void modify(int k, int x) { for(int i = k; i <= n; i += lowbit(i)) tr[i] += x; } int query(int k) { int res = 0; for(int i = k; i; i -= lowbit(i)) res += tr[i]; return res; } int find(int x) { int l = 1, r = n; while(l < r) { int mid = l + r >> 1; if(query(mid) >= x) r = mid; else l = mid + 1; } return l; } void init() { for(int i = 1; i <= n; i++) modify(i, 1); } int main() { scanf("%d", &n); for(int i = 2; i <= n; i++) scanf("%d", &a[i]); init(); for(int i = n; i >= 1; i--) { int pos = find(a[i] + 1); h[i] = pos; modify(pos, -1); } for(int i = 1; i <= n; i++) printf("%d\n", h[i]); return 0; }
2.由于这道题的特殊性,(所有涉及到的区间都是我们已经预设好的区间)我们还可以用倍增法来求解
#include <iostream> #include <stdio.h> #include <algorithm> #include <string> #include <cmath> #define For(i, j, n) for (int i = j; i <= n; ++i) using namespace std; const int N = 1e5 + 5; int lowbit(int x) { return x & (-x); } int n, a[N], tr[N], h[N]; void modify(int k, int x) { for (int i = k; i <= n; i += lowbit(i)) tr[i] += x; } int query(int k) { int res = 0; for (int i = k; i; i -= lowbit(i)) res += tr[i]; return res; } void init() { scanf("%d", &n); for (int i = 2; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= n; i++) modify(i, 1); } void solve() { int p, s, sum; int base = log2(n); for (int i = n; i; i--) { p = 0; sum = 0; for(s = base; s >= 0; s--) if(p + (1 << s) <= n && sum + tr[p + (1 << s)] < a[i] + 1) { p += 1 << s; sum += tr[p]; } h[i] = p + 1; modify(h[i], -1); } } int main() { init(); solve(); for (int i = 1; i <= n; i++) printf("%d\n", h[i]); return 0; }