题目简化后,召唤师能控制n种元素,并且将m个元素组合成一个新技能(这m个元素旋转或反转都算作一个,如123,132,312等),那么召唤师能组合多少技能,20000>=n>=1,10000>=m>=1,由于结果可能很大,请将结果对1000000007取余。
输入:3 3
输出:10
说明:111,112,113,122,123,133,222,223,233,333
代码一:
import sys
res = 0
def dfs(start,k,n,tmp):
global res
if k == 0:
res = (res + 1) % 1000000007
return
for i in xrange(start,n+1):
if not tmp or i >= tmp[-1]:
tmp.append(i)
dfs(i, k - 1, n, tmp)
tmp.pop()
def combine(n,k):
global res
dfs(1,k,n,[])
return res
n,k = 4,3
print combine(n,k)
可以发现,tmp仅记录合法序列,并比较最后一个,考虑用一个pre去代替tmp
优化1
import sys
res = 0
sys.setrecursionlimit(20001)
def dfs(start,k,n,pre):
global res
if k == 0:
res = (res + 1) % 1000000007
return
for i in xrange(start,n+1):
if not pre or i >= pre:
dfs(i, k - 1, n, i)
def combine(n,k):
global res
# 注意传进去的pre为0
dfs(1,k,n,0)
return res
#n,k = 20000,10000
n,k = 4,3
print combine(n,k)
进一步可以发现,pre和i的关系很大相关,
if not pre or i >= pre
dfs(i, k - 1, n, i)
第一行主要保证下一层的递归,从pre-n+1去选择,但第二行传进去i作为pre,同i作为start,天然就能保证下一层递归的(start,n+1)循环中i >=pre,因此也可以去掉if判断。
优化2:
import sys
res = 0
sys.setrecursionlimit(20001)
def dfs(start,k,n):
global res
if k == 0:
res = (res + 1) % 1000000007
return
for i in xrange(start,n+1):
dfs(i, k - 1, n)
def combine(n,k):
global res
# 注意没有了参数pre
dfs(1,k,n)
return res
#n,k = 20000,10000
n,k = 4,3
print combine(n,k)
该算法时间复杂度O(n),空间复杂度O(k),
但是如题中,当n,k = 20000,10000,耗时比较大,不一定能AC。