题目链接
每个奶牛都有一个编号,1- N 从第二个牛开始给出前面比她编号小的牛的个数,问你求牛的编号序列
从后往前看,最后一头牛可以确定它的号码,因为知道了前面有k头比它小的,k+1即为它号码。记a[i]为第i头牛在它前面有多少头牛号码比它小的(即输入值),那么如何计算第k-1头牛的编号?
我们从1到N进行遍历,记录 a [ k − 1 ] a[k-1] a[k−1]个没有访问过的编号(没有访问过即没有被他之后的牛 a [ k ] a[k] a[k]所使用的编号),那么第 a [ k ] a[k] a[k]个编号即该牛的编号,整个过程如下所示
#define inf 0x3f3f3f3f #define ll long long #define vec vector<int> #define P pair<int,int> #define MAX 8005 int N, vis[MAX], r[MAX], a[MAX]; int main() { while (scanf("%d", &N) != EOF) { a[0] = 0; for (int i = 1; i < N; i++)scanf("%d", &a[i]); memset(vis, 0, sizeof(vis)); memset(r, 0, sizeof(r)); for (int i = N - 1; i >= 0; i--) { int cnt = 0; for (int j = 1; j <= N; j++) { if (!vis[j]) { if (cnt == a[i]) { r[i] = j; vis[j] = 1; break; } cnt++; } } } for (int i = 0; i < N; i++) cout << r[i] << endl; } }当然这样做的复杂度显然是 N 2 N^2 N2的,这道题勉强可过,但是数据一多就凉了,因此我们可以进行进一步的优化,我们可以用树状数组表示每个编号前面有多少个没被占用,然后用二分找到答案。
#define lobit(x) x&-x int c[8001],n,a[8001],ans[8001]; void add(int x,int num) { while(x<=n) { c[x]+=num; x+=lobit(x); } } int ask(int x) { int sum=0; while(x) { sum+=c[x]; x-=lobit(x); } return sum; } int low(int x)//二分答案 { int l=1,r=n; while(l<=r) { int mid=(l+r)/2; if(ask(mid)+x<=mid) r=mid-1; else l=mid+1; } return l; } int main() { scanf("%d",&n); a[1]=0; for(int i=2;i<=n;i++) scanf("%d",&a[i]); for(int i=n;i>=1;i--) { int w=low(a[i]+1);//找到位置 ans[i]=w;//记录答案 add(w,1);//占用该位置 } for(int i=1;i<=n;i++) printf("%d\n",ans[i]); }