【问题标题】:Number of Positive Solutions to a1 x1+a2 x2+......+an xn=k (k<=10^18)a1 x1+a2 x2+......+an xn=k (k<=10^18) 的正解数
【发布时间】:2011-12-20 20:24:49
【问题描述】:

问题是 a1 x1+a2 x2+....+an xn=k 的解数,有约束:1)ai>0 and ai0 and n=0 我能够制定一个动态编程解决方案,但是对于 n>10^10,它运行的时间太长了。请指导我获得更有效的解决方案。 代码

int dp[]=new int[16];
        dp[0]=1;
        BigInteger seen=new BigInteger("0");
        while(true)
        {
            for(int i=0;i<arr[0];i++)
            {
                if(dp[0]==0)
                    break;
                dp[arr[i+1]]=(dp[arr[i+1]]+dp[0])%1000000007;
            }
            for(int i=1;i<15;i++)
                dp[i-1]=dp[i];
            seen=seen.add(new BigInteger("1"));
            if(seen.compareTo(n)==0)
            break;
        }
        System.out.println(dp[0]);

arr 是包含系数的数组,答案应该是 mod 1000000007,因为方法的数量不适合 int。

【问题讨论】:

  • 感谢您的回复。但是这个优化还不够,因为上面的代码运行 O(k) 并且 k 是 10^18。所以任何对运行时间的优化都将不胜感激。
  • 请解释dp[i] 包含的内容,以及代码中的哪一点是正确的。
  • 我记得看到过这个问题的精确解决方案,但它涉及到一些分析(泰勒级数)。我一回到家就检查这个。
  • @Serdalis 通过n &amp; mask 计算n % m 是可能的当且仅当m 是2 的幂,在这种情况下mask = m-1
  • @Serdalis 这不可能……

标签: algorithm combinatorics dynamic-programming


【解决方案1】:

针对实际问题的更新:

实际问题要简单得多。但是,如果不完全破坏它,就很难提供帮助。

将其简化为基本要素,问题是

给定 k 个不同的正整数 L1、...、Lk 和一个非负整数 n,如何存在许多不同的有限序列 (a1, ..., ar) 1. 对于所有 i (1 i r),aiLj 和 2 之一。a1 + ... + ar = n。 (换句话说,ncompositions 的数量仅使用给定的 Lj。)

为方便起见,您还被告知所有 Lj 都是 k n n 呈指数增长,您将没有足够的内存来存储大 的确切数字n),您应该只计算序列计数模 1000000007 的余数。

要解决这样的问题,首先要从最简单的情况开始。最简单的情况是当只给出一个 L 时,如果 nL 的倍数并且不可接受,那么显然有一个可接受的序列如果 n mod L != 0 的序列。这还没有帮助。所以考虑下一个最简单的情况,给出两个 L 值。假设它们是 1 和 2。

  1. 0 有一个组合,空序列:N(0) = 1
  2. 1 有一个组成,(1): N(1) = 1
  3. 2 有两个组成,(1,1); (2): N(2) = 2
  4. 3 有三个组成,(1,1,1);(1,2);(2,1): N(3) = 3
  5. 4 有五个组成,(1,1,1,1);(1,1,2);(1,2,1);(2,1,1);(2,2):N( 4) = 5
  6. 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 = 112*4 + 1*3 = 11 算作两种不同的解决方案。

首先是一些符号。对于数字的 m 元组,让&lt; | &gt; 表示规范双线性对,即
&lt;a|x&gt; = a_1*x_1 + ... + a_m*x_m。对于正整数 B,令A_B = {1, 2, ..., B} 为不超过 B 的正整数的集合。令 N 表示自然数的集合,即非负整数。
对于0 &lt;= m, kB &gt; 0,让C(B,m,k) = card { (a,x) \in A_B^m × N^m : &lt;a|x&gt; = 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 &lt;= m &lt;= 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 &lt;= d_B(k) &lt;= B。对于B = 2,显然是d_2(k) = 1 if k is odd, 2 if k is evend_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 &gt;= 2不再是周期性的,但是有简单的公式可以从C(B,m,r)得到C(B,m,q*P+r)。因此,在已知 C(B,1,_) = d_BC(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 &lt;= m &lt;= 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 为模,则这种情况成立。

【讨论】:

  • 非常感谢您的回复。我非常感谢您耐心回答我的问题。但我不得不说您的解决方案对我来说很复杂。另外您提到您的解决方案需要几个小时k 在 10^18 范围内。我正在寻找一个在 7 秒内完成的解决方案。
  • @DineshReddy This one,我怀疑?这是一个不同的问题,解决起来更快。如果是这样,我可以在不完全破坏问题的情况下找出我可以给出的提示。
  • 是的,就是这个问题。请帮帮我
  • 欧拉计划的丹尼尔,是你吗?
猜你喜欢
  • 2015-06-04
  • 1970-01-01
  • 2016-02-04
  • 1970-01-01
  • 2012-12-02
  • 1970-01-01
  • 2020-04-25
  • 2019-11-27
  • 2020-01-28
相关资源
最近更新 更多