多多鸡打算造一本自己的电子字典,里面的所有单词都只由a和b组成。
每个单词的组成里a的数量不能超过N个且b的数量不能超过M个。
多多鸡的幸运数字是K,它打算把所有满足条件的单词里的字典序第K小的单词找出来,作为字典的封面。
共一行,三个整数N, M, K。(0 < N, M < 50, 0 < K < 1,000,000,000,000,000)
共一行,为字典序第K小的单词。
2 1 4
ab
满足条件的单词里,按照字典序从小到大排列的结果是
a
aa
aab
ab
aba
b
ba
baa
对于40%的数据:0 < K < 100,000
对于100%的数据:0 < K < 1,000,000,000,000,000
题目保证第K小的单词一定存在
由不同的前缀a
和b
构成了两个子树,找第k个元素实际上就是先序遍历的过程,通过求子树中的唯一字符串个数可以快速地跳过一些无关的子树。
直接先序遍历往往会有过大的时间复杂度,可以通过带备忘录的递归算法求解出f(n,m)的值,从而避免大量的重复运算。
Base case:只有m或n不为零,则直接返回对应的值。
# 计算包含N个a和M个b的子字典树包含的unique字符串的个数,从而和K进行 # 比较,以便选择跳过该子树或者进入该子树 count_dict = {} def calc_subtree_str_num(N,M): if (N,M) in count_dict.keys(): return count_dict[(N,M)] elif N == 0: count_dict[(N,M)] = M elif M == 0: count_dict[(N,M)] = N else: #分别以a和b得到的两个子树的个数统计加上a和b这两个节点 count_dict[(N,M)] = calc_subtree_str_num(N-1,M) + calc_subtree_str_num(N,M-1) + 2 return count_dict[(N,M)] def main(): N,M,K = list(map(int,input().split())) res = "" #当K=0时就找到了对应的字符串 while K > 0: # 一般情况 N 和 M 都存在 if N > 0 and M > 0: #获取当前情况下左子树的字符串个数,如果大于K说明结果在右子树 left_str_cnt = calc_subtree_str_num(N-1, M)+1 if K <= left_str_cnt: # 说明第k个在a子树下,添加字符'a',并继续循环向下判断 res += 'a' K -= 1 N -= 1 else: # 在右子树下,K可以跳过left_str_cnt+1个值,1为左子树根节点'a',配合上前缀也是一个unique的str res += 'b' K -= (left_str_cnt + 1) M -= 1 #其他情况,N=0或者M=0时只需要一直添加字符即可,因为题上的说明不用考虑不存在 elif N == 0 and M > 0: res += 'b' K -= 1 M -= 1 elif M == 0 and N > 0: res += 'a' K -= 1 N -= 1 return res print(main())