Luogu6620 组合数问题 - 第二类斯特林数 -

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

题解:
其实就一个式子
image

证明可以利用这个式子找一下规律 $$k\binom{n}{k}=n\binom{n-1}{k-1}$$

回到原题,把多项式拆开之后的形式就是开头式子左边的部分,利用得到的式子可以直接\(O(m^2logm)\)的计算

事实上,一个幂可以转化成下降幂的和,系数多一个第二类斯特林数
image
另外,原式的证明也可以利用求导

\[(1+x)^n=\sum_{k=0}^n\binom{n}{k}x^k \]

如果左右都取二阶导,则有

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

同乘一个 \(i\) 即可

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f;

int n,x,mod,m;
int S[1005][1005];

int pw(int x,int y){
	if(!y)return 1;
	if(y==1)return x;
	int mid=pw(x,y>>1);
	if(y&1)return 1ll*mid*mid%mod*x%mod;
	return 1ll*mid*mid%mod;
}
int C[1005][1005],a[1005];

signed main(){
	scanf("%d%d%d%d",&n,&x,&mod,&m);
	for(int i=0;i<=m;i++)scanf("%d",&a[i]);
	S[1][1] = 1;
	for(int i=2;i<=1000;i++)
		for(int j=1;j<=1000;j++)
			(S[i][j] = S[i-1][j-1]+1ll*j*S[i-1][j]%mod) %= mod;
	C[0][0] = 1;
	for(int i=1;i<=1000;i++){
		C[i][0] = 1;
		for(int j=1;j<=i;j++)C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mod;
	}
	
	ll ans = 1ll * a[0] * pw(x+1, n) % mod;
	for(int p=1;p<=m;p++){
		int cans = 0, ndown = n;
		for(int i=1;i<=p;i++){
			(cans += 1ll * ndown * S[p][i] % mod * pw(x,i) % mod * pw(1+x,n-i) % mod) %= mod;
			ndown = 1ll*ndown * (n-i) % mod;
		}
		(ans += 1ll*cans*a[p]%mod) %= mod;
	}
	cout<<ans;

	return 0;
}
posted @ 2022-12-29 15:45  SkyRainWind  阅读(13)  评论(0编辑  收藏  举报