把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷6620】[省选联考 2020 A 卷] 组合数问题(下降幂)

点此看题面

大致题意: 给定\(n,x\)和一个\(m\)次多项式\(f(k)\),求\(\sum_{k=0}^nf(k)\times x^k\times C_n^k\)

下降幂

首先不难想到要把\(f(k)\)拆开。

然而,这道题妙就妙在,它的第一步是把\(f(k)\)转化为下降幂形式,即令:

\[f(k)=\sum_{i=0}^ma_ik^i=\sum_{i=0}^mb_ik^{\underline{i}} \]

由于此处\(m\le1000\),因此我们只要\(O(m^2)\)暴力转就可以了。

关于第二类斯特林数与下降幂有一个公式:

\[x^n=\sum_{i=0}^nS2(n,i)\times x^{\underline{i}} \]

(根据式子本身意义理解,左式\(x^n\)就是假设所有盒子本质不同的方案数,右式就是枚举非空盒子个数求出对应方案数)

所以可以得到:

\[f(k)=\sum_{i=0}^ma_ik^i=\sum_{i=0}^ma_i\sum_{j=0}^iS2(i,j)k^{\underline{j}}=\sum_{i=0}^m(\sum_{j=i}^mS2(j,i)\times a_j)k^{\underline{i}} \]

即:

\[b_i=\sum_{j=i}^mS2(j,i)\times a_j \]

推式子

好了,现在我们已经把\(f(k)\)转化成了下降幂形式,接着就是把它代入:

\[\sum_{k=0}^n\sum_{i=0}^mb_ik^{\underline{i}}\times x^k\times C_n^k \]

显然把\(i\)的枚举调到前面去得到:

\[\sum_{i=0}^mb_i\sum_{k=0}^nk^{\underline{i}}\times x^k\times C_n^k \]

接下来介绍一个新的公式:

\[k^{\underline{i}}\times C_n^k=n^{\underline{i}}\times C_{n-i}^{k-i} \]

证明就是暴拆:

\[k^{\underline{i}}\times C_n^k=\frac{k!}{(k-i)!}\times \frac{n!}{k!(n-k)!}=\frac{n!}{(k-i)!(n-k)!} \]

\[n^{\underline{i}}\times C_{n-i}^{k-i}=\frac{n!}{(n-i)!}\times \frac{(n-i)!}{(k-i)!(n-k)!}=\frac{n!}{(k-i)!(n-k)!} \]

套用这个公式得到:

\[\sum_{i=0}^mb_in^{\underline{i}}\sum_{k=0}^n C_{n-i}^{k-i}\times x^k \]

由于\(k-i<0\)时组合数没用,因此索性令\(k\)枚举\(k-i\),得到:

\[\sum_{i=0}^mb_in^{\underline{i}}\sum_{k=0}^{n-i} C_{n-i}^k\times x^{k+i} \]

\(x^{k+i}\)中提出一个\(x_i\)

\[\sum_{i=0}^mb_in^{\underline{i}}x^i\sum_{k=0}^{n-i} C_{n-i}^k\times x^{k} \]

然后后面这家伙显然就是一个二项式定理啊:

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

于是就做完了,这个式子可以直接暴力算。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define M 1000
using namespace std;
int n,m,x,X,a[M+5],b[M+5],Fac[M+5],S2[M+5][M+5];
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
	RI i,j;scanf("%d%d%d%d",&n,&x,&X,&m);
	for(S2[0][0]=i=1;i<=m;++i) for(S2[i][0]=0,j=1;j<=i;++j) S2[i][j]=(1LL*S2[i-1][j]*j+S2[i-1][j-1])%X;//预处理第二类斯特林数
	for(i=0;i<=m;++i) scanf("%d",a+i);for(i=0;i<=m;++i) for(j=i;j<=m;++j) b[i]=(1LL*S2[j][i]*a[j]+b[i])%X;//多项式转下降幂
	RI t=0,n_=1;for(i=0;i<=m;n_=1LL*n_*(n-i)%X,++i) t=(1LL*b[i]*n_%X*QP(x,i)%X*QP(x+1,n-i)+t)%X;//计算答案,n_记录n的i次下降幂
	return printf("%d\n",t),0;//输出答案
}
posted @ 2020-07-29 16:26  TheLostWeak  阅读(221)  评论(0编辑  收藏  举报