【 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<cstdio>
#include<cstring>
#include<algorithm>
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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值