Hihocoder [Offer收割]编程练习赛49 题目4 : 第K小先序遍历

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

有一棵包含N个节点的二叉树,节点编号是1~N。  

现在我们知道它的中序遍历结果A1, A2, ... AN。

只有中序遍历显然不能确定一棵二叉树的形态,可能有很多棵不同的二叉树符合给定的中序遍历。  

那么你能从中找出先序遍历结果字典序第K小的二叉树吗?  

设先序遍历结果是P1, P2, ... PN。字典序最小指首先P1应尽量小,其次P2尽量小,再次P3尽量小…… 以此类推。

输入

第一行包含两个整数N和K。

以下N行每行包含一个整数Ai。

对于30%的数据,1 ≤ N ≤ 12  

对于100%的数据,1 ≤ N ≤ 30 1 ≤ K ≤ 合法的二叉树总数 1 ≤ Ai ≤ N

输出

输出N行,依次是P1, P2, ... PN。代表第K小的先序遍历结果。

样例输入
5 2  
5  
4  
1  
3  
2
样例输出
1  
4  
5  
3  
2

思路:
从小到大枚举当前区间的点值,则以其为根的方案数为h[i - s] * h[e - i],其中s, e, i分别为区间左端点,右端点,当前点,h[len]表示长为len的先序遍历总共能对应多少种先序遍历序列。(我们在最初先把k减1,这会使之后的运算更方便)
如果h[i - s] * h[e - i] < k,
说明不可能以当前点作为根,那么k减去这个值,然后继续处理直至找到根。然后递归处理两个子区间,其中第一个区间的k1 = k / h[e - i], 第二个区间的k2 = k % h[e - i]。
其中h可以n^2 dp求,dp[i] = SUM(dp[j] * dp[i - 1 - j])(0 <= j < i)。实际上,他就是一个卡特兰数。其第30项大概是个16位数,可在long long范围内求解。
(比赛时算错了范围,用最近重新学的java写了下高精度,麻烦了不少,一种强行秀java的既视感...另这场Rank5,坐等HR小姐姐打电话,美滋滋~)
 1 import java.io.*;
 2 import java.util.*;
 3 import java.math.*;
 4 
 5 public class Main {
 6     
 7     static int n;
 8     static BigInteger k;
 9     static int a[] = new int[35];
10     static int p[] = new int[35];
11     static BigInteger A[] = new BigInteger[35];
12     
13     public static void get_A() {
14         A[0] = BigInteger.ONE;
15         for (int i = 1; i <= 30; ++i) {
16             A[i] = BigInteger.ZERO;
17             for (int j = 0; j < i; ++j) {
18                 A[i] = A[i].add(A[j].multiply(A[i - 1 - j]));
19             }
20             System.out.println(A[i]);
21         }
22     }
23     
24     public static void solve(BigInteger k, int s, int e) {
25         
26         if (s > e) {
27             return;
28         }
29         
30         if (s == e) {
31             System.out.println(a[s]);
32             return;
33         }
34         
35         List<Integer> arr = new ArrayList<Integer>();
36         Set<Integer> ss = new TreeSet<Integer>();
37         
38         for (int i = s; i <= e; ++i) {
39             ss.add(a[i]);
40         }
41         
42         for (Integer x : ss) {
43             arr.add(x);
44         }
45         
46         for (int i = 0; i <= e - s; ++i) {
47             int x = arr.get(i);
48             int pos = p[x];
49             BigInteger pa = A[pos - s];
50             BigInteger pb = A[e - pos];
51             BigInteger pm = pa.multiply(pb);
52             if (pm.compareTo(k) <= 0) {
53                 k = k.subtract(pm);
54             } else {
55                 BigInteger k1 = k.divide(pb);
56                 BigInteger k2 = k.mod(pb);
57                 System.out.println(x);
58                 solve(k1, s, pos - 1);
59                 solve(k2, pos + 1, e);
60                 return;
61             }
62         }
63     }
64     
65     public static void main(String args[]) throws Exception {
66         get_A();
67         Scanner cin = new Scanner(System.in);
68         n = cin.nextInt();
69         k = cin.nextBigInteger();
70         for (int i = 1; i <= n; ++i) {
71             a[i] = cin.nextInt();
72             p[a[i]] = i;
73         }
74         solve(k.subtract(BigInteger.ONE), 1, n);
75         cin.close();
76     }
77 }
78 /*
79 6 6
80 6 5 4 3 2 1
81 */

 

posted @ 2018-03-04 15:21  hit_yjl  阅读(182)  评论(0编辑  收藏  举报