输入描述:
共一行,三个整数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)