[省选联考 2020 A 卷] 组合数问题

\(\text{Problem}:\)[省选联考 2020 A 卷] 组合数问题

\(\text{Solution}:\)

前言:[清华集训2016] 如何优雅地求和 的弱化版。

由二项式定理,有 \(\sum\limits_{k=0}^{n}x^{k}\binom{n}{k}=(x+1)^{n}\)。这提示我们想要改变 \(f(k)\),使得式子中出现 \(\sum x^k\binom{n}{k}\) 的形式。那么可以将普通多项式转下降幂多项式,设 \(f(k)=b_{0}+b_{1}k^{\underline{1}}+b_{2}k^{\underline{2}}+\cdot\cdot\cdot +b_{m}k^{\underline{m}}\),有:

\[\begin{aligned} \sum\limits_{k=0}^{n}f(k)\times x^{k}\times\binom{n}{k}&=\sum\limits_{k=0}^{n}\sum\limits_{i=0}^{\min\{k,m\}}b_{i}k^{\underline{i}}\times x^{k}\times \binom{n}{k}\\&=\sum\limits_{k=0}^{n}\sum\limits_{i=0}^{\min\{k,m\}}b_{i}\times x^{k}\times \binom{n-i}{k-i}\times n^{\underline{i}} \end{aligned} \]

对于第二步转化,将 \(k^{\underline{i}}\)\(\binom{n}{k}\) 都展开,\(k!\) 抵消后即可。

现在考虑改变枚举顺序:

\[\sum\limits_{i=0}^{m}b_{i}\times n^{\underline{i}} \left(\sum\limits_{k=i}^{n}x^{k}\times \binom{n-i}{k-i}\right) \]

\(k\)\(k-i\) 代替,提取 \(x^{i}\),可以得到:

\[\sum\limits_{i=0}^{m}b_{i}\times n^{\underline{i}}\times x^{i} \left(\sum\limits_{k=0}^{n-i}x^{k}\times \binom{n-i}{k}\right) \]

终于出现了我们想要的形式,利用二项式定理,得到:

\[\sum\limits_{i=0}^{m}b_{i}\times n^{\underline{i}}\times x^{i}\times (x+1)^{n-i} \]

在已知序列 \(b\) 的情况下,可以在 \(O(m\log x)\) 的时间内求出答案。问题转化为将普通多项式改为下降幂多项式。

引理:\(x^n=\sum\limits_{i=0}^{n}{n\brace i}x^{\underline{i}}\)

考虑 \(x^n\) 的组合意义:把 \(n\) 个物体随意放在 \(x\) 个位置。枚举 \(x\) 个位置中哪些被选择,有:

\[x^n=\sum\limits_{i=0}^{n}\binom{x}{i}{n\brace i}i!=\sum\limits_{i=0}^{n}{n\brace i}x^{\underline{i}} \]

第二类斯特林数:将 \(n\) 个不同物体划分成 \(k\) 个集合的方案数。由于位置有顺序关系,所以还要乘上 \(i!\)。于是可以得到上式,证毕。

对于多项式 \(f(k)=a_{0}+a_{1}k+a_{2}k^2+\cdot\cdot\cdot+a_{m}k^m\),考虑展开 \(k^{i}\),得到:

\[f(k)=\sum\limits_{i=0}^{m}\left(\sum_{j=0}^{i}a_{i}{i\brace j}x^{\underline{j}}\right) \]

那么预处理第二类斯特林数,暴力给 \(x^{\underline{j}}\) 加上对应的系数即可。总时间复杂度 \(O(m^2)\)

对于 [清华集训2016] 如何优雅地求和 这题,做法完全相同。但是 \(m\) 范围略大,需要多项式科技(也有大力推式子得到 \(O(m)\) 递推的做法,此处不表)。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=1010;
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int n,X,Mod,m,a[N],b[N],S[N][N],res;
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=1ll*x*x%Mod) if(p&1) res=1ll*res*x%Mod; return res; }
signed main()
{
	n=read(), X=read(), Mod=read(), m=read();
	for(ri int i=0;i<=m;i++) a[i]=read();
	S[0][0]=1;
	for(ri int i=1;i<=m;i++)
	{
		for(ri int j=1;j<=i;j++)
		{
			S[i][j]=(S[i-1][j-1]+1ll*j*S[i-1][j]%Mod)%Mod;
		}
	}
	for(ri int i=0;i<=m;i++)
	{
		for(ri int j=0;j<=i;j++)
		{
			b[j]=(b[j]+1ll*a[i]*S[i][j]%Mod)%Mod;
		}
	}
	int now=1;
	for(ri int i=0;i<=min(n,m);i++)
	{
		res=(res+1ll*b[i]*now%Mod*ksc(X,i)%Mod*ksc(X+1,n-i)%Mod)%Mod;
		now=1ll*now*(n-i)%Mod;
	}
	printf("%d\n",res);
	return 0;
}
posted @ 2021-04-15 22:21  zkdxl  阅读(75)  评论(0编辑  收藏  举报