牛客网 多多的电子字典

题目:多多鸡打算造一本自己的电子字典,里面的所有单词都只由a和b组成。
每个单词的组成里a的数量不能超过N个且b的数量不能超过M个。
多多鸡的幸运数字是K,它打算把所有满足条件的单词里的字典序第K小的单词找出来,作为字典的封面。

输入描述:
共一行,三个整数N, M, K。(0 < N, M < 50, 0 < K < 1,000,000,000,000,000)

输出描述:
共一行,为字典序第K小的单词。
示例1
输入
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小的单词一定存在

题解:

动态规划的状态是:dp[m][n]表示m个a n个b时候的单词数,dp[m][n] = dp[m][n - 1] + dp[m-1][n] + 2
来源:牛客网

我来解释一下为什么其他回答的递归为dp[m][n] = dp[m][n - 1] + dp[m-1][n] + 2
假设m个a,n个b:
那么假定第一个字母为a,这种的的个数为dp[m - 1][n] + 1 (额外加1是为了包括总长度为1,也就是只有这个a后面没有的情况, 即'a')
那么假定第一个字母为b,这种的个数为dp[m][n - 1] + 1 (额外的1是为了包括总长度为1的情况,即'b')
所以,dp[m][n] = dp[m][n - 1] + dp[m-1][n] + 2。

比如dp[1][1] = dp[0][1] + dp[1][0] + 2 ,表示"一个a一个b" = "a开头,一个b" + "b开头,一个a" + 2
dp[1][1]表示1个a一个b,这种的可能有a,ab,b,ba。
dp[0][1]表示一个b,这种的可能有b。 (对应a开头,也就是ab)
dp[1][0]表示1个a,这种的可能有a。 (对应b开头,也就是ba)
显然还有a b没有算,这就是上面式子中的+2

给出代码

# @牛奶泡泡糖 https://www.nowcoder.com/profile/33750295
def getcount(map,m,n):
    if not m:
        map[(m,n)]=n
    if not n:
        map[(m,n)]=m
    elif (m,n) in map:
        return map[(m,n)]
    else:
        #+'a'就是getcount(map,m-1,n)+1,加'b'同理
        map[(m,n)]=getcount(map,m-1,n)+getcount(map,m,n-1)+2
    return map[(m,n)]


def mink(n,m,k):
    cur=""
    map= {}
    while k>0 :
        if n>0 and m==0:#只有'a'存在
            k-=1
            cur+="a"
            n-=1
        elif m>0 and n==0: #只有'b'存在
            cur+='b'
            k-=1
            m-=1
        elif n>0 and m>0 :#都存在时
            #计算a下所有子节点的和
            cnt=getcount(map,n-1,m) +1
            if cnt>=k:#在a子树下
                cur+='a'
                k-=1 #k相当于横向遍历,每次向右遍历一个节点
                n-=1
            else:#在b子树下
                cur+='b'
                m-=1
                k-=(cnt+1) #k要减去a子树的所有节点个数
    return cur


from collections import defaultdict

ss=list(map(int,input().split()))
n=ss[0]
m=ss[1]
k=ss[2]
p=mink(n,m,k) 
print(p)












种一棵树最好的时间是十年前,其次是现在。
原文地址:https://www.cnblogs.com/islch/p/13458439.html