【 2016北京集训测试赛(十七)】crash的游戏【组合数】【斯特林数】

题意:求
∑ i = 0 m C m i × C n + 2 i − m k \sum_{i=0}^{m} C_{m}^{i}\times C_{n+2i-m}^{k} i=0mCmi×Cn+2imk
其中 n , m ≤ 1 0 9 n,m\le10^{9} n,m109 k ≤ 300 k\le300 k300。共 T T T组数据, T ≤ 500 T\le500 T500
题解:
推式子!
首先,我们想到
C x k = ∏ i = 0 k − 1 x − i k − i C_{x}^{k}=\prod_{i=0}^{k-1}\frac{x-i}{k-i} Cxk=i=0k1kixi
如果 k k k是一个常数,那么 C x k C_{x}^{k} Cxk可以表示成一个以 x x x为未知数的 k k k次多项式。
所以我们可以令
C x k = ∑ i = 1 k a i x i C_{x}^{k}=\sum_{i=1}^{k}a_{i}x^{i} Cxk=i=1kaixi
因为每组数据的 k k k都是给定的,所以我们可以在 O ( k 2 ) O(k^2) O(k2)的时间内算出 a a a
     ∑ i = 0 m C m i × C n + 2 i − m k \ \ \ \ \sum_{i=0}^{m} C_{m}^{i}\times C_{n+2i-m}^{k}     i=0mCmi×Cn+2imk
= ∑ i = 0 m × ∑ j = 1 k a j × ( n + 2 i − m ) j =\sum_{i=0}^{m}\times\sum_{j=1}^{k}a_{j}\times(n+2i-m)^{j} =i=0m×j=1kaj×(n+2im)j
= ∑ j = 1 k a j ∑ i = 0 m ( n + 2 i − m ) j =\sum_{j=1}^{k}a_{j}\sum_{i=0}^{m}(n+2i-m)^{j} =j=1kaji=0m(n+2im)j
我们二项式展开一下。
= ∑ j = 1 k a j ∑ i = 0 m ∑ t = 0 j C j t ( n − m ) t ( 2 i ) j − t =\sum_{j=1}^{k}a_{j}\sum_{i=0}^{m}\sum_{t=0}^{j}C_{j}^{t}(n-m)^{t}(2i)^{j-t} =j=1kaji=0mt=0jCjt(nm)t(2i)jt
= ∑ j = 1 k a j ∑ t = 0 j C j t ( n − m ) t × 2 j − t ∑ i = 0 m C m i × i j − t =\sum_{j=1}^{k}a_{j}\sum_{t=0}^{j}C_{j}^{t}(n-m)^{t}\times 2^{j-t}\sum_{i=0}^{m}C_{m}^{i}\times i^{j-t} =j=1kajt=0jCjt(nm)t×2jti=0mCmi×ijt
我们令 f ( n , k ) = ∑ i = 0 n C n i × i k f(n,k)=\sum_{i=0}^{n}C_{n}^{i}\times i^{k} f(n,k)=i=0nCni×ik
则原式
= ∑ j = 1 k a j ∑ t = 0 j C j t ( n − m ) t × 2 j − t f ( m , j − t ) =\sum_{j=1}^{k}a_{j}\sum_{t=0}^{j}C_{j}^{t}(n-m)^{t}\times 2^{j-t}f(m,j-t) =j=1kajt=0jCjt(nm)t×2jtf(m,jt)
我们看一看怎么求 f f f
      f ( n , k ) = ∑ i = 0 n C n i × i k \ \ \ \ \ f(n,k)=\sum_{i=0}^{n}C_{n}^{i}\times i^{k}      f(n,k)=i=0nCni×ik
= ∑ i = 0 n C n i × ∑ j = 0 k s ( k , j ) × C i j × j ! =\sum_{i=0}^{n}C_{n}^{i}\times \sum_{j=0}^{k}s(k,j)\times C_{i}^{j} \times j! =i=0nCni×j=0ks(k,j)×Cij×j! s ( k , j ) s(k,j) s(k,j)为第二类斯特林数。
= ∑ j = 0 k s ( k , j ) × j ! ∑ i = 0 n C n i × C i j =\sum_{j=0}^{k}s(k,j)\times j!\sum_{i=0}^{n}C_{n}^{i}\times C_{i}^{j} =j=0ks(k,j)×j!i=0nCni×Cij
= ∑ j = 0 k s ( k , j ) × j ! C n j × 2 n − j =\sum_{j=0}^{k}s(k,j)\times j!C_{n}^{j}\times2^{n-j} =j=0ks(k,j)×j!Cnj×2nj
其中 C n i × C i j C_{n}^{i}\times C_{i}^{j} Cni×Cij就相当于先选 j j j个,剩下的随便选。
于是就可以预处理一下,愉快地计算啦!
总时间复杂度 O ( T k 2 ) O(Tk^{2}) O(Tk2)

#include #include #include using namespace std; const int N=305,mod=1000000007,inv2=500000004; int t,n,m,k,s[N][N],a[N],jc[N],C[N][N],c[N],f[N],tmp[N]; int fastpow(int a,int x){ int res=1; while(x){ if(x&1){ res=1LL*res*a%mod; } x>>=1; a=1LL*a*a%mod; } return res; } int main(){ C[0][0]=s[0][0]=1; for(int i=1;i<=300;i++){ C[i][0]=1; for(int j=1;j<=i;j++){ C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; s[i][j]=(s[i-1][j-1]+1LL*s[i-1][j]*j)%mod; } } scanf("%d",&t); while(t--){ scanf("%d%d%d",&n,&m,&k); memset(a,0,sizeof(a)); memset(f,0,sizeof(f)); jc[0]=c[0]=1; for(int i=1;i<=k;i++){ jc[i]=1LL*jc[i-1]*i%mod; c[i]=1LL*c[i-1]*(m-i+1)%mod*fastpow(i,mod-2)%mod; } f[0]=fastpow(2,m); for(int i=1;i<=k;i++){ for(int j=0,base=f[0];j<=i;j++,base=1LL*base*inv2%mod){ f[i]=(f[i]+1LL*s[i][j]*jc[j]%mod*c[j]%mod*base)%mod; } } a[0]=1; for(int i=0;i<k;i++){ tmp[0]=0; for(int j=1;j<=i+1;j++){ tmp[j]=(a[j-1]-1LL*i*a[j]%mod+mod)%mod; } for(int j=0;j<=i+1;j++){ a[j]=tmp[j]; } } for(int i=1;i<=k;i++){ a[i]=1LL*a[i]*fastpow(jc[k],mod-2)%mod; } int ans=0; for(int i=1;i<=k;i++){ for(int j=0,b1=1,b2=fastpow(2,i);j<=i;j++,b1=1LL*b1*(n-m)%mod,b2=1LL*b2*inv2%mod){ ans=(ans+1LL*a[i]*C[i][j]%mod*b1%mod*b2%mod*f[i-j])%mod; } } printf("%d\n",ans); } return 0; } 

你可能感兴趣的:(斯特林数,组合数)