P6620[省选联考2020A卷]组合数问题【组合数学,斯特林数】

正题

题目链接:https://www.luogu.com.cn/problem/P6620


题目大意

给出\(n,x,p,m\)和一个\(m\)次多项式\(f\)

\[\sum_{k=0}^nf(k)\times x^k\times \binom{n}{k} \]

答案对\(p\)取模。

\(1\leq n\leq 10^9,1\leq m\leq 1000\)


解题思路

什么混凝土数学题

首先我们发现这个组合数\(\binom{n}{k}\)处理的十分难受,有一个下降幂的结论正好可以把这个难受的\(k\)变掉。

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

我们需要找到一个东西来提供\(k^{\underline m}\),此时给我们的多项式\(f\)就是一个不错的选择。

我们考虑把多项式转换为下降幂的形式

\[f(x)=\sum_{i=0}^ma_ix^i=\sum_{i=0}^mb_ix^{\underline i} \]

考虑一下怎么找到序列\(b_i\),也就是我们需要把\(x^i\)转换为下降幂的形式,有一个第二类斯特林数的性质就是

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

\[\sum_{i=0}^ma_ix^i=\sum_{i=0}^ma_i\sum_{j=0}^i{\begin{Bmatrix}i\\j\end{Bmatrix}}x^{\underline j}\Rightarrow b_i=\sum_{i=j}^n{\begin{Bmatrix}j\\i\end{Bmatrix}}x^{\underline{i}} \]

然后就可以继续推我们的式子了

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

\[\sum_{k=0}^n\sum_{i=0}^mb_ix^k\binom{n-i}{k-i}n^{\underline i} \]

\(i\)提出去枚举

\[\sum_{i=0}^mb_in^{\underline i}\sum_{k=0}^nx^k\binom{n-i}{k-i} \]

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

然后后面那个式子就可以二项式定理了

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

然后就搞定了

时间复杂度\(O(m^2+m\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1100;
ll n,x,m,P,a[N],b[N],s[N][N],ans;
ll power(ll x,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*x%P;
		x=x*x%P;b>>=1;
	}
	return ans;
}
signed main()
{
	scanf("%lld%lld%lld%lld",&n,&x,&P,&m);
	for(ll i=0;i<=m;i++)scanf("%lld",&a[i]);
	s[0][0]=1; 
	for(ll i=1;i<=m;i++)
		for(ll j=1;j<=i;j++)
			s[i][j]=(s[i-1][j]*j%P+s[i-1][j-1])%P;
	for(ll i=0;i<=m;i++)
		for(ll j=i;j<=m;j++)
			(b[i]+=a[j]*s[j][i]%P)%=P;
	for(ll i=0,tmp=1;i<=m;i++){
		(ans+=b[i]*tmp%P*power(x,i)%P*power(x+1,n-i)%P)%=P;
		tmp=tmp*(n-i)%P;
	}
	printf("%lld\n",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/QuantAsk/p/14578690.html