针对实际问题的更新:
实际问题要简单得多。但是,如果不完全破坏它,就很难提供帮助。
将其简化为基本要素,问题是
给定 k 个不同的正整数 L1、...、Lk 和一个非负整数 n,如何存在许多不同的有限序列 (a1, ..., ar) 1. 对于所有 i (1 i r),ai 是 Lj 和 2 之一。a1 + ... + ar = n。 (换句话说,n 的 compositions 的数量仅使用给定的 Lj。)
为方便起见,您还被告知所有 Lj 都是 k n n 呈指数增长,您将没有足够的内存来存储大 的确切数字n),您应该只计算序列计数模 1000000007 的余数。
要解决这样的问题,首先要从最简单的情况开始。最简单的情况是当只给出一个 L 时,如果 n 是 L 的倍数并且不可接受,那么显然有一个可接受的序列如果 n mod L != 0 的序列。这还没有帮助。所以考虑下一个最简单的情况,给出两个 L 值。假设它们是 1 和 2。
- 0 有一个组合,空序列:N(0) = 1
- 1 有一个组成,(1): N(1) = 1
- 2 有两个组成,(1,1); (2): N(2) = 2
- 3 有三个组成,(1,1,1);(1,2);(2,1): N(3) = 3
- 4 有五个组成,(1,1,1,1);(1,1,2);(1,2,1);(2,1,1);(2,2):N( 4) = 5
- 5 有八个组成,(1,1,1,1,1);(1,1,1,2);(1,1,2,1);(1,2,1,1); (2,1,1,1);(1,2,2);(2,1,2);(2,2,1): N(5) = 8
您现在可能会看到它,或者需要更多术语,但您会注意到您得到了斐波那契数列(移动了一个),N(n) = F( n+1),因此序列N(n)满足递归关系
N(n) = N(n-1) + N(n-2) (对于n > = 2;我们还没有证明,到目前为止,这是一个基于模式发现的假设)。现在,我们可以在不计算许多值的情况下看到这一点吗?当然,有两种类型的可接纳序列,以 1 结尾的和以 2 结尾的。由于可接纳序列的划分只限制了最后一个元素,即 ad 的数量。下一个与 n 相加并以 1 结尾的是 N(n-1) 和广告的数量。下一个求和到 n 并以 2 结尾是 N(n-2)。
这个推理立即推广,给定 L1 L2 Lk,对于所有 n >= Lk,我们有
N(n) = N(n-L1) + N(n-L2) + ... + N(n-Lk)
如果我们只对 N(n) % m 感兴趣,那么这个解释很明显。
嗯,线性递归仍然将计算 N(n) 作为 O(n) 任务吗?
是的,但是研究一些提到的关键字很快就会导致算法只需要 O(log n) 步;)
错误解释问题的算法,不再相关,但可能仍然很有趣:
这个问题看起来有点 SPOJish,所以我不会给出一个完整的算法(至少,在我用谷歌搜索一下它是否是一个竞赛问题之前,我不会给出一个完整的算法)。我希望在描述中没有遗漏任何限制,例如这种表示的排列应该只对计数贡献一个,这会使事情变得相当复杂。所以我把1*3 + 2*4 = 11 和2*4 + 1*3 = 11 算作两种不同的解决方案。
首先是一些符号。对于数字的 m 元组,让< | > 表示规范双线性对,即
<a|x> = a_1*x_1 + ... + a_m*x_m。对于正整数 B,令A_B = {1, 2, ..., B} 为不超过 B 的正整数的集合。令 N 表示自然数的集合,即非负整数。
对于0 <= m, k 和B > 0,让C(B,m,k) = card { (a,x) \in A_B^m × N^m : <a|x> = k }。
然后你的问题是找到\sum_{m = 1}^15 C(15,m,k)(模1000000007)。
为了完整起见,让我们提一下C(B,0,k) = if k == 0 then 1 else 0,这可能有助于理论上的考虑。对于和数为正的情况,我们很容易找到递归公式
C(B,m+1,k) = \sum_{j = 0}^k C(B,1,j) * C(B,m,k-j)
通过归纳,C(B,m,_) 是 m 个因子 C(B,1,_) 的卷积¹。计算直到k 的两个已知函数的卷积是O(k^2),因此如果已知C(B,1,_),则给出O(n*k^2) 算法来计算C(B,m,k), 1 <= m <= n。对小 k 来说没问题,但我们的银河系不会看到你这样计算 C(15,15,10^18)。那么,我们能做得更好吗?好吧,如果您熟悉拉普拉斯变换,您就会知道类似的变换会将卷积乘积转换为逐点乘积,这更容易计算。然而,尽管在这种情况下变换很容易计算,但反之则不然。还有什么想法吗?为什么,是的,让我们仔细看看C(B,1,_)。
C(B,1,k) = card { a \in A_B : (k/a) is an integer }
换句话说,C(B,1,k) 是k 的除数不超过B。让我们用d_B(k) 表示。很明显1 <= d_B(k) <= B。对于B = 2,显然是d_2(k) = 1 if k is odd, 2 if k is even。 d_3(k) = 3 当且仅当 k 可被 2 和 3 整除,因此当且仅当 k 是 6 的倍数,d_3(k) = 2 当且仅当 2、3 之一除以 k 而不是另一个时,即当且仅当 k % 6 \in {2,3,4} 和最后,d_3(k) = 1 当且仅当 2 或 3 均不除 k,即当且当当 gcd(k,6) = 1,当且当 k % 6 \in {1,5}。所以我们已经看到d_2 与周期2 是周期性的,d_3 与周期6 是周期性的。通常,类似推理表明d_B 对所有B 都是周期性的,最小正周期除以B!。
给定C(B,1,_) = d_B的任意正周期P,我们可以在卷积中拆分总和(k = q*P+r, 0
C(B,m+1, q*P+r) = \sum_{c = 0}^{q-1} (\sum_{j = 0}^{P-1} d_B(j)*C(B,m,(q-c)*P + (r-j)))
+ \sum_{j = 0}^r d_B(j)*C(B,m,r-j)
函数C(B,m,_)对于m >= 2不再是周期性的,但是有简单的公式可以从C(B,m,r)得到C(B,m,q*P+r)。因此,在已知 C(B,1,_) = d_B 和 C(B,m,_) 到 P 的情况下,计算 C(B,m+1,_) 到 P 是一个 O(P^2) 任务²,获取计算任意大 k 的 C(B,m+1,k) 所需的数据,需要 m 个这样的卷积,因此这是O(m*P^2).
然后找到C(B,m,k) 为1 <= m <= n 和任意大的k 是O(n^2*P^2),在时间和O(n^2*P) 在空间。
对于 B = 15,我们有 15! = 1.307674368 * 10^12,因此将其用于 P 是不可行的。幸运的是,d_15 的最小正周期要小得多,所以你得到了一些可行的东西。从粗略的估计来看,我仍然希望C(15,15,k) 的计算以小时而不是秒为单位更合适,但它比O(k) 有所改进,O(k) 需要数年时间(k 在 10^18 区域内)。
¹这里使用的卷积是(f \ast g)(k) = \sum_{j = 0}^k f(j)*g(k-j)。
² 假设所有算术运算都是O(1);如果像在 OP 中一样,只需要以某个 M > 0 为模的余数,则如果所有中间计算都以 M 为模,则这种情况成立。