如何计算均匀间隔二项式系数的和

时间:2014-04-10 21:57:26

标签: c++ math combinations binomial-coefficients

如何找到模数为M的均匀间隔二项式系数之和? 即。 ( n C a + n C a + r + n C a + 2r + n C a + 3r + ... + n C a + kr )%M =?
给定:0 <= a&lt; r,a + kr&lt; = n&lt; a +(k + 1)r,n < 10 5 ,r&lt; 100个

我的第一次尝试是:

int res = 0;
int mod=1000000009;
for (int k = 0; a + r*k <= n; k++) {
    res = (res + mod_nCr(n, a+r*k, mod)) % mod;
}

但效率不高。所以看完here后 而paper我发现上述金额相当于:
求和[ω -ja *(1 +ω j n / r],0 <= j <1。 R等并且ω= e i2π/ r 是原始r th 的统一根。
在订单(r)中找到这笔金额的代码是什么?

编辑: n可以达到10 5 ,r可以达到100。

4 个答案:

答案 0 :(得分:1)

二项式系数是多项式(1 + x)^ n的系数。 x ^ a,x ^(a + r)等的系数之和是多项式mod x ^ r-1的环中的(1 + x)^ n中的x ^ a的系数。多项式mod x ^ r-1可以由长度为r的系数阵列指定。您可以通过repeated squaring计算(1 + x)^ n mod(x ^ r-1,M),在每一步减少mod x ^ r-1和mod M.这需要大约log_2(n)r ^ 2步和O(r)空间与天真的乘法。如果使用快速傅里叶变换对多项式进行乘法或取幂,则速度会更快。

例如,假设n = 20且r = 5。

(1+x)    = {1,1,0,0,0}
(1+x)^2  = {1,2,1,0,0}
(1+x)^4  = {1,4,6,4,1}
(1+x)^8  = {1,8,28,56,70,56,28,8,1} 
           {1+56,8+28,28+8,56+1,70}
           {57,36,36,57,70}
(1+x)^16 = {3249,4104,5400,9090,13380,9144,8289,7980,4900}
           {3249+9144,4104+8289,5400+7980,9090+4900,13380}
           {12393,12393,13380,13990,13380}

(1+x)^20 = (1+x)^16 (1+x)^4
         = {12393,12393,13380,13990,13380}*{1,4,6,4,1}
           {12393,61965,137310,191440,211585,203373,149620,67510,13380}
           {215766,211585,204820,204820,211585}

这告诉你a的5个可能值的总和。例如,对于a = 1,211585 = 20c1 + 20c6 + 20c11 + 20c16 = 20 + 38760 + 167960 + 4845。

答案 1 :(得分:0)

类似的东西,但你必须检查anr,因为我只是在没有关于条件的情况下放了任何东西:

#include <complex>
#include <cmath>
#include <iostream>

using namespace std;

int main( void )
{
    const int r = 10;
    const int a = 2;
    const int n = 4;

    complex<double> i(0.,1.), res(0., 0.), w;

    for( int j(0); j<r; ++j )
    {
        w = exp( i * 2. * M_PI / (double)r );

        res += pow( w, -j * a ) * pow( 1. + pow( w, j ), n ) / (double)r;
    }

    return 0;

}

答案 2 :(得分:0)

mod操作很昂贵,尽量避免使用

uint64_t res = 0;
int mod=1000000009;
for (int k = 0; a + r*k <= n; k++) {
    res += mod_nCr(n, a+r*k, mod);
    if(res > mod)
        res %= mod;
}

我没有测试此代码

答案 3 :(得分:0)

我不知道您在这个问题上是否达到目标,但是实现此公式的关键是实际找出w ^ i是独立的,因此可以形成一个环。简单来说,您应该考虑实施 (1 + x)^ n%(x ^ r-1)或在环Z [x] /(x ^ r-1)中找出(1 + x)^ n 如果感到困惑,我现在将为您提供一个简单的实现。

  1. 制作一个大小为r的向量。 O(r)空间+ O(r)时间

  2. 在每个O(r)空间+ O(r)时间初始化为零的矢量

  3. 将该向量的前两个元素设为1 O(1)

  4. 使用快速求幂方法计算(x + 1)^ n。每个乘法取O(r ^ 2),因此有log n个乘法,因此O(r ^ 2 log(n))

  5. 返回向量的第一个元素O(1) 复杂 O(r ^ 2 log(n))时间和O(r)空间。 可以使用傅立叶变换将该r ^ 2简化为r log(r)。 乘法是如何完成的,这是幂中具有mod的规则多项式乘法

    向量p1(r,0); 向量p2(r,0); p1 [0] = p1 [1] = 1; p2 [0] = p2 [1] = 1; 现在我们要做乘法 向量res(r,0); for(int i = 0; i