Luogu6620 组合数问题 - 第二类斯特林数 -
题目链接:https://www.luogu.com.cn/problem/P6620
题解:
其实就一个式子
证明可以利用这个式子找一下规律 $$k\binom{n}{k}=n\binom{n-1}{k-1}$$
回到原题,把多项式拆开之后的形式就是开头式子左边的部分,利用得到的式子可以直接\(O(m^2logm)\)的计算
事实上,一个幂可以转化成下降幂的和,系数多一个第二类斯特林数
另外,原式的证明也可以利用求导
\[(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;
}