首先注意你拥有的每种颜色的块数是一个完整的红鲱鱼,因为 10^100 > N 总是。所以每种颜色的块数实际上是无限的。
现在请注意,在每个位置,p(如果有有效的配置,则不留空格等)必须有一个颜色块,c。这个块有len[c] 的方式可以撒谎,所以它仍然在这个位置上,p。
我的想法是在固定位置尝试所有可能的颜色和位置(N/2,因为它将范围减半),然后对于每种情况,在此固定颜色块之前有 b 单元格,之后有 a这个固定色块。因此,如果我们定义一个函数ways(i),它返回平铺i 单元格的方法数(使用ways(0)=1)。那么在某个位置用固定色块平铺多个单元格的方法数为ways(b)*ways(a)。将所有可能的配置相加得出ways(i) 的答案。
现在我选择了固定位置为N/2,因为它将范围减半,您最多可以将范围减半ceil(log(N)) 次。现在,由于您要移动一个关于N/2 的块,您必须从N/2-750 计算到N/2-750,其中750 是一个块可以具有的最大长度。因此,您必须计算大约 750*ceil(log(N))(由于方差而更多)长度才能得到最终答案。
因此,为了获得良好的性能,您必须完成记忆,因为这本质上是一种递归算法。
所以用Python(因为我很懒,不想写大数的类):
T = int(raw_input())
for case in xrange(T):
#read in the data
C = int(raw_input())
lengths = map(int, raw_input().split())
minlength = min(lengths)
n = int(raw_input())
#setup memoisation, note all lengths less than the minimum length are
#set to 0 as the algorithm needs this
memoise = {}
memoise[0] = 1
for length in xrange(1, minlength):
memoise[length] = 0
def solve(n):
global memoise
if n in memoise:
return memoise[n]
ans = 0
for i in xrange(C):
if lengths[i] > n:
continue
if lengths[i] == n:
ans += 1
ans %= 100000007
continue
for j in xrange(0, lengths[i]):
b = n/2-lengths[i]+j
a = n-(n/2+j)
if b < 0 or a < 0:
continue
ans += solve(b)*solve(a)
ans %= 100000007
memoise[n] = ans
return memoise[n]
solve(n)
print "Case %d: %d" % (case+1, memoise[n])
请注意,我没有对此进行详尽的测试,但如果您将此算法翻译成 C++ 或类似的语言,我很确定它会满足 20 秒的时间限制。
编辑:使用N = 10^15 和长度为750 的块运行测试我知道memoise 包含大约60000 元素,这意味着solve(n) 的非查找位被调用的次数大致相同.