看别人的思路:
从后往前推,排在最后一头牛比他编号小的数量有x头牛,那么最后一头牛的编号必然为x+1。
按照这种思路下去,我们把1-n编号的牛排成一排。把x+1这头牛从里面删除。
假如倒数第二头牛在他前面比他编号小的数量有y头牛,那么就在这1-n删掉了求出来的牛后剩下的第y+1头牛。
方法一:直接搜索(n*n)
p[i]表示第i个应该放的cow的id。
f[i]=0表示此牛还未被删除,f[i]=1表示此牛已经被删除。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int n; int a[8010]; int p[8010]; int f[8010]; int main() { scanf("%d",&n); int i =1; a[1]=1; for(i=2;i<=n;i++) { scanf("%d",&a[i]); } a[1]=0; for(i=n;i>0;i--) { int k = 0; int j =0; for(j=1;j<=n;j++) if(f[j]==0) { k++; if(k==a[i]+1) break; } p[i]=j; f[j]=1;//dele k-th cow } for(i=1;i<=n;i++) printf("%d/n",p[i]); }
方法二:线段树(n*lgn)
搜索排在第n位的数是几时可用线段树实现 ,对于一个线段树中的所代表的线段[a,b],结点中的数值纪录[a,b]中还有多少人没有被去掉,记为len,所以对于一个在剩余数字队列中排在第n位,看这个人是在一个结点的左子树中还是右子树中。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; struct node { int l,r; int cnt;//在[l,r]区间中的个数 }tree[16*1024]; int save[8010]; int a[8010]; void build(int l,int r,int u) { tree[u].l=l; tree[u].r=r; tree[u].cnt = r-l+1; if(l<r) { build(l,(l+r)/2,2*u); build((l+r)/2+1,r,2*u+1); } } void del(int c,int root) { if(tree[root].l==tree[root].r) { save[++save[0]]=tree[root].l; tree[root].cnt=0; return; } if(c<=tree[2*root].cnt) del(c,2*root); else del(c-tree[2*root].cnt,2*root+1); tree[root].cnt--; } int main() { int n ; scanf("%d",&n); int i =0; a[1]=0; for(i=2;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); for(i=n;i>=1;i--) del(a[i]+1,1); for(i=save[0];i>=1;i--) printf("%d/n",save[i]); }