首先注意你拥有的每种颜色的块数是一个完整的红鲱鱼,因为 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
因此您必须计算 fromN/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)
调用次数大约相同。