Lost Cows
Time Limit: 1000MS |
|
Memory Limit: 65536K |
Total Submissions: 4143 |
|
Accepted: 2575 |
Description
N (2 <= N <= 8,000) cows have unique brands in the range 1..N. In a spectacular display of poor judgment, they visited the neighborhood 'watering hole' and drank a few too many beers before dinner. When it was time to line up for their evening meal, they did not line up in the required ascending numerical order of their brands.
Regrettably, FJ does not have a way to sort them. Furthermore, he's not very good at observing problems. Instead of writing down each cow's brand, he determined a rather silly statistic: For each cow in line, he knows the number of cows that precede that cow in line that do, in fact, have smaller brands than that cow.
Given this data, tell FJ the exact ordering of the cows.
Input
* Line 1: A single integer, N
* Lines 2..N: These N-1 lines describe the number of cows that precede a given cow in line and have brands smaller than that cow. Of course, no cows precede the first cow in line, so she is not listed. Line 2 of the input describes the number of preceding cows whose brands are smaller than the cow in slot #2; line 3 describes the number of preceding cows whose brands are smaller than the cow in slot #3; and so on.
Output
* Lines 1..N: Each of the N lines of output tells the brand of a cow in line. Line #1 of the output tells the brand of the first cow in line; line 2 tells the brand of the second cow; and so on.
Sample Input
5
1
2
1
0
Sample Output
2
4
5
3
1
Source
基本思路:
求一个从1-n的整数的序列,满足题目所给的要求。题目给出了n-1个ai的值,ai=m表示在第i(1<i<=n)个数的前面有m个数比第i个数小。我们要求的就是这第i个数是多少。所以只能从后往前找,因为在要求的序列中n个数必须且只能出现一次。然后就不断的查找,删除,最后求出整个序列。 数据,n=
5
0
2
2
1
首先从最后一个开始,表示第5个数前面有一个数小于它,所以这个数一定是2(因为每个数都要出现),然后是倒数第二个 ,表示第4个数字前面有2个数字小于第四个数,说明这个数字是在剩下的数字(除去这个数字以后的所有数字)里的名次排在第3(有两个比他小)。所以类推,从最后个数字开始,求出一个删除一个,第i个要求的数字就是当前所有(i个,前面已经找到了的删除掉)数字排在第ai+1的数字。
显然,如果直接查找然后删除是可以完成的,但是时间复杂度为O(n^2),而题目是数据很大(n<8000),显然要超时。所以需要改进,不要整体操作,用线段数是很好的方法,可以将复杂读降低到O(n*log n).具体如下:
1#include<iostream>
2using namespace std;
3int k,bj;
4struct stu
5{
6 int len,rig; //len为左儿子,rig右儿子
7 int s; //表示有多少个数字
8}a[30000];
9void Lost(int n) //建立线段树Lost,其实是一个中根遍历二叉树
10{ //先遍历根结点,然后遍历左结点,最后遍历右结点
11 k++;
12 int j=k;
13 a[j].s=n;
14 if(n==1) //当n=1的时候说明只有一个数,
15 {
16 a[j].len=bj++; //用此结点的左儿子表示这个
17 a[j].rig=-1; // 并用右儿子rig=-1作标记;
18 return ;
19 }
20 int i;
21 i=n/2;
22 a[j].len=k+1;
23 Lost(i);
24 a[j].rig=k+1;
25 Lost(n-i);
26}
27void Delete(int i,int n) //删除过程,其实也是一个查找过程,具有两个功能 :
28{ // 查找和删除要求的点结点
29 a[i].s--; //相当于删除一个点,所以总数减少1
30 if(a[i].rig==-1) // gig=-1说明到了叶子结点,查找完成
31 {
32 bj=a[i].len;
33 return ;
34 }
35 int j=a[i].len;
36 if(n<=a[j].s)
37 {
38 Delete(j,n);
39 return ;
40 }
41 else Delete(a[i].rig,n-a[j].s);
42}
43int main()
44{
45 int n,i;
46 int num1[8010],num2[8010];
47 while(scanf("%d",&n)!=EOF)
48 {
49 k=-1;bj=1;
50 Lost(n);
51 num2[0]=0;
52 for(i=1;i<n;i++)
53 scanf("%d",&num2[i]);
54 for(i=n-1;i>=0;i--)
55 {
56 Delete(0,num2[i]+1);
57 num1[i]=bj;
58 }
59 for(i=0;i<n;i++)
60 printf("%d\n",num1[i]);
61 }
62 return 0;
63}
64
65
66