LGP6620 [PUTS 2020A] 组合数问题 学习笔记

LGP6620 [PUTS 2020A] 组合数问题 学习笔记

Luogu Link

题意简述

计算 \(\sum_{k=0}^{n}f(k)\times x^k \times \begin{pmatrix}n\\ k\end{pmatrix}\)\(p\) 取模的值。

其中,\(f(k)\) 为一给定的 \(m\) 次多项式 \(f(k)=a_0+a_1k+a_2k^2+\dots+a_mk^m\)

\(n,x,p\le 10^9,m\le 10^3\)

做法解析

蒟蒻不语,只是一味贺 这篇题解

666 \(n,x,p\) 仨玩意梅怡阁诗人。只有 \(m\) 的数据范围还算拟人,果断猜想正解复杂度一定是只和 \(m\) 有关的,比如 \(O(m^2)\)。然而我怎么能把这一大坨式子的复杂度绑到 \(m\) 上面呢?

如果有一定的混凝土数学储备,这时候就会想到有个叫下降幂的东西。下降幂和组合数有这样一个性质:

\[\dbinom{n}{k}\times k^{\underline{m}}=\dbinom{n-m}{k-m}\times n^{\underline{m}} \]

证明就是把两边都拆开,然后发现都消掉了。总之很优美。

然后普通多项式转下降幂多项式用到斯特林数,这玩意刚好是 \(O(M^2)\) 的。这启示我们要做出来这题下降幂和斯特林数必不可少。

假设我们成功把 \(f(k)\) 转成了下降幂多项式,那么就有:

\[\sum_{i=0}^{m}b_ik^{\underline{i}}\times x^k\times\dbinom{n}{k}=\sum_{i=0}^{m}b_ix^k\dbinom{n-i}{k-i}n^{\underline{i}} \]

则原式可化为:

\[\sum_{k=0}^{n}\sum_{i=0}^{m}b_ix^k\dbinom{n-i}{k-i}n^{\underline{i}}=\sum_{i=0}^{m}b_in^{\underline{i}}\sum_{k=0}^{n}\dbinom{n-i}{k-i}x^k \]

发现 \(k\) 枚举到 \(i\) 以下是没有意义的,于是再把式子化一下得到

\[\sum_{i=0}^{m}b_in^{\underline{i}}\sum_{k=i}^{n}\dbinom{n-i}{k-i}x^k=\sum_{i=0}^{m}b_in^{\underline{i}}\sum_{k=0}^{n-i}\dbinom{n-i}{k}x^{k+i} \]

再把 \(x^i\) 提出来得到:

\[\sum_{i=0}^{m}b_in^{\underline{i}}x^i\sum_{k=0}^{n-i}\dbinom{n-i}{k}x^{k} \]

啪一下很快啊!我们发现里面那玩意似乎就是个二项式定理的样子!
如果看不出来的话我们给 \(n-i\) 换元为 \(t\)

\[\sum_{k=0}^t\dbinom{t}{k}x^t=(x+1)^t \]

这甚至还是 \(b=1\) 的特殊形式下的式子。

好好好,现在原式就可以化为

\[\sum_{i=0}^{m}b_in^{\underline{i}}x^i(x+1)^{n-i} \]

  • 好了,还有什么人,要提问?
  • 我要。
  • 他来了。
  • 我算普通多项式转下降幂多项式,好吗?
  • ao

普通多项式转下降幂多项式这部分就是混凝土数学基本功了。直接上柿子,由:

\[x^n=\sum_{i=0}^n\begin{Bmatrix}n\\ i\end{Bmatrix} x^{\underline{i}} \]

可推得:

\[\sum_{i=0}^{m}a_ik^i=\sum_{i=0}^{m}a_i\sum_{j=0}^{i}x^{\underline{j}}=\sum_{i=0}^{m}k^{\underline{i}}\sum_{j=i}^m\begin{Bmatrix}j\\ i\end{Bmatrix}a_j \]

(这一步转换有点难度,这么理解:显然在中式中,\(x^{\underline{j}}\)\(i\in[j,m]\) 的时候被算了)

也就是说 $$b_i=\sum_{j=i}^{m}\begin{Bmatrix}j\ i\end{Bmatrix}a_j$$

斯特林数 \(O(M^2)\) 递推。
啊啊这道题到此终于做完了。

最后我们算的柿子就是:

\[\sum_{i=0}^m\Big(\big(\sum_{j=i}^{m}\begin{Bmatrix}j\\ i\end{Bmatrix}a_j\big)\times n^{\underline{i}}x^i(x+1)^{n-i}\Big) \]

这道题就做完了!

代码实现

题目并不保证 \(p\) 是质数,所以不能用费马小定理快速幂求逆元!我在这卡了一个小时 \(QAQ\)

#include <bits/stdc++.h>
using namespace std;
namespace obasic{
    typedef long long lolo;
    template <typename _T>
    void readi(_T &x){
        _T k=1;x=0;char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-')k=-1;
        for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
        x*=k;return;
    }
    template <typename _T>
    void writi(_T x){
        if(x<0)putchar('-'),x=-x;
        if(x>9)writi(x/10);
        putchar(x%10+'0');
    }
};
using namespace obasic;
const int MaxM=1e3+5;
lolo N,X,P,M,A[MaxM],B[MaxM];
lolo ssn[MaxM][MaxM],fans,xpo[MaxM];
namespace omathe{
    lolo fastpow(lolo a,lolo b,lolo p){
        lolo res=1;
        for(;b;(a*=a)%=p,b>>=1)if(b&1)(res*=a)%=p;
        return res;
    }
    lolo getinv(lolo a,lolo p){
        return fastpow(a,p-2,p);
    }
};
using namespace omathe;
int main(){
    readi(N),readi(X),readi(P),readi(M);
    for(int i=0;i<=M;i++)readi(A[i]);
    ssn[0][0]=1;
    for(int i=1;i<=M;i++){
        for(int j=1;j<=M;j++){
            ssn[i][j]=(ssn[i-1][j-1]+j*ssn[i-1][j]%P)%P;
        }
    }
    xpo[M]=fastpow(X+1,N-M,P);
    for(int i=M-1;~i;i--)xpo[i]=xpo[i+1]*(X+1)%P;
    lolo cans,tmp1=1,tmp2=1;
    for(int i=0;i<=M;(tmp1*=(N-i))%=P,(tmp2*=X)%=P,i++){
        for(int j=i;j<=M;j++)(B[i]+=ssn[j][i]*A[j]%P)%=P;
        cans=B[i]*tmp1%P*tmp2%P*xpo[i]%P,(fans+=cans)%=P;
    }
    writi(fans);
    return 0;
}

反思总结

但是,为什么这道题要这么思考呢?

笔者和同机房巨佬 \(w9095\) 进行了这样的交流:

我:巨佬,你有什么对这道题更高妙的理解吗?我感觉这道题的思考过程好像就是因为 \(m\) 小然后就套路想到斯特林数之类的……
\(w9095\):呃是这样的:据我所知,我在OI里碰见高次项(本题中就是 \(x^k\))一般就两种想法,要么把它留在那,用某种方式预处理掉(线性筛、反演等等);要么直接让它滚蛋,用斯特林数转下降幂,然后这玩意有很好的组合性质。
我:所以说在化下降幂、柿子推到那前你也看不出来那个二项式定理形式是吧。
\(w9095\):是的,就是式子推到那了,然后发现其“恰好”满足二项式定理的形式。

posted @ 2025-02-14 16:55  矞龙OrinLoong  阅读(21)  评论(0)    收藏  举报