1. 程式人生 > >[2016北京集訓測試賽17]crash的遊戲-[組合數+斯特林數+拉格朗日插值]

[2016北京集訓測試賽17]crash的遊戲-[組合數+斯特林數+拉格朗日插值]

想是 memset \n pac ash pri string 。。 多項式

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); } }

[2016北京集訓測試賽17]crash的遊戲-[組合數+斯特林數+拉格朗日插值]