如何计算等距二项式系数的和

How to compute sum of evenly spaced binomial coefficients

本文关键字:二项式 何计算 计算      更新时间:2023-10-16

如何求取M的等距二项式系数之和
即(nCa+nCa+rnCa+2r+nCa+3r+…+nCa+kr)%M=
给定:0<=a<r、 a+kr<=n<a+(k+1)r、n<105,r<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;
}

但这不是有效的。所以看完这里在这篇论文中,我发现上述总和相当于:
求和[ω-ja*(1+ωjn/r],对于0<=j<rω=ei2π/r是单位的原始rOrder(r)中查找此和的代码是什么

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

原始问题来源:https://www.codechef.com/APRIL14/problems/ANUCBC
竞赛问题的社论:https://discuss.codechef.com/t/anucbc-editorial/5113
在6年后重新访问这篇文章后,我记不起我是如何将最初的问题陈述转化为我的版本的,尽管如此,我还是分享了原始解决方案的链接,以防有人想看看正确的解决方案。

二项式系数是多项式(1+x)^n的系数。x^a,x^(a+r)等的系数之和是多项式mod x^r-1中的(1+x)^n中的x^a的系数。多项式mod x^r-1可以由长度为r的系数数组指定。你可以通过重复平方来计算(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。

类似的东西,但你必须检查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;
}

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;
}

我没有测试这个代码

我不知道你在这个问题上是否达成了共识,但实现这个公式的关键是要真正弄清楚w^I是独立的,因此可以形成一个环。简单地说,你应该考虑实现(1+x)^n%(x^r-1)或在环Z[x]/(x^r-1)中求出(1+x)^n如果感到困惑,我现在就给你一个简单的实现。

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

  2. 用0初始化这个向量,每个位置O(r)空间+O(r)时间

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

  4. 用快速求幂法计算(x+1)^n。每次乘法取O(r^2),有logn次乘法,因此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<r;i++){for(int j=0;j<r;j++){res[(i+j)%r]+=(p1[i]*p2[j]);}}返回res[0];我以前已经实现了这一部分,如果你还对一些事情感兴趣,请告诉我。我更希望您自己实现代码,但如果您需要代码,请告诉我。