zoukankan      html  css  js  c++  java
  • 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 */
  • 相关阅读:
    组件间通信
    Android抓包方法(一)之Fiddler代理
    汉字转拼音
    post请求参数问题
    post请求参数设置
    swagger
    IfcPresentationDefinitionResource(介绍定义资源)
    Java计算两个日期之间的时间差(毫秒数)
    IfcPresentationAppearanceResource(外观定义资源)
    IfcMeasureResource(度量资源)
  • 原文地址:https://www.cnblogs.com/BIGTOM/p/8504796.html
Copyright © 2011-2022 走看看