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 */