[2016北京集训测试赛17]crash的游戏-[组合数+斯特林数+拉格朗日插值]
Description
Solution
核心思想是把组合数当成一个奇怪的多项式,然后拉格朗日插值。。;哦对了,还要用到第二类斯特林数(就是把若干个球放到若干个盒子)的一个公式:
$x^{n}=\sum _{i=0}^{n}C(n,i)*i!*S(i,x)$
围观大佬博客(qaq公式太难打了)
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int mod=1e9+7; const int N=310; ll fac[N],finv[N],inv[N],S[N][N],inv2; int n,m,k; ll C(int x,int y){return x<0||y<0||x-y<0?0:fac[x]*finv[y]%mod*finv[x-y]%mod;} ll ksm(ll x,int k){ll re=1;while (k){if (k&1) re=re*x%mod;k>>=1;x=x*x%mod;}return re;} ll a[N]; void geta(int k) { memset(a,0,sizeof(a)); a[0]=1; for (int i=0;i<k;a[0]=0,i++) for (int j=i+1;j;j--) a[j]=(a[j-1]-i*a[j]%mod+mod)%mod; for (int i=0;i<=k;i++) a[i]=a[i]*finv[k]%mod; } ll bin[N],pnm[N]; void pre(int k) { pnm[0]=1;for (int i=1;i<=k;i++) pnm[i]=pnm[i-1]*(n+m)%mod; bin[0]=1;for (int i=1;i<=k;i++) bin[i]=bin[i-1]*(mod-2)%mod; } ll f[N]; ll ans; int main() { inv2=ksm(2,mod-2); inv[0]=inv[1]=fac[0]=fac[1]=finv[0]=finv[1]=1; for (int i=2;i<=300;i++) fac[i]=fac[i-1]*i%mod,inv[i]=(mod-mod/i)*inv[mod%i]%mod; for (int i=2;i<=300;i++) finv[i]=finv[i-1]*inv[i]%mod; S[0][0]=1; for (int i=1;i<=300;i++) for (int j=1;j<=i;j++) S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%mod; int T; scanf("%d",&T); while (T--) { scanf("%d%d%d",&n,&m,&k); ans=0; pre(k);geta(k); ll cnt=ksm(2,m); for (int i=0;i<=k;i++) { ll s=0,Cmj=1,m_j=cnt; for (int j=0;j<=i;j++) { s+=S[i][j]*fac[j]%mod*Cmj%mod*m_j%mod; Cmj=Cmj*(m-j)%mod*inv[j+1]%mod; m_j=m_j*inv2%mod; } f[i]=s%mod; } for (int i=0;i<=k;i++) { ll s=0; for (int t=0;t<=i;t++) s+=C(i,t)*bin[i-t]%mod*pnm[t]%mod*f[i-t]%mod; ans+=s%mod*a[i]%mod; } printf("%lld\n",ans%mod); } }