crash的游戏 - 组合数学 - 斯特林数

题目大意:求:
i = 0 m ( m i ) ( n + m 2 i k ) \sum_{i=0}^m\binom mi\binom {n+m-2i}{k}
m 1 0 9 , k 300 , m + k n 1 0 9 m\le10^9,k\le300,m+k\le n\le10^9 。500组数据。
题解:
直接暴做。
首先注意到 ( x k ) \binom x k 是一个关于 x x k k 次多项式,设 ( x k ) = i = 0 k a i x i \binom xk=\sum_{i=0}^ka_ix^i ,则:
i = 0 m ( m i ) ( n + m 2 i k ) = i = 0 m ( m i ) j = 0 k a j ( n + m 2 i ) j = i = 0 k a i j = 0 m ( m j ) ( n + m 2 j ) i = i = 0 k a i j = 0 m ( m j ) t = 0 i ( i t ) ( n + m ) t ( 2 j ) i t = i = 0 k a i t = 0 i ( i t ) ( n + m ) t ( 2 ) i t j = 0 m ( m j ) j i t = i = 0 k a i t = 0 i ( i t ) ( n + m ) t ( 2 ) i t f i t ( m ) \sum_{i=0}^m\binom mi\binom {n+m-2i}{k}\\ =\sum_{i=0}^m\binom mi\sum_{j=0}^k a_j(n+m-2i)^j\\= \sum_{i=0}^ka_i\sum_{j=0}^m\binom mj(n+m-2j)^i\\= \sum_{i=0}^ka_i\sum_{j=0}^m\binom mj\sum_{t=0}^i\binom it(n+m)^t(-2j)^{i-t}\\ =\sum_{i=0}^ka_i\sum_{t=0}^i\binom it(n+m)^t(-2)^{i-t}\sum_{j=0}^m\binom mjj^{i-t}\\ =\sum_{i=0}^ka_i\sum_{t=0}^i\binom it(n+m)^t(-2)^{i-t}f_{i-t}(m)
其中:
f k ( n ) = i = 0 n ( n i ) i k = i = 0 n ( n i ) j = 0 k S ( k , j ) ( i j ) j ! = i = 0 k S ( k , i ) i ! j = 0 n ( n j ) ( j i ) = i = 0 k S ( k , i ) i ! ( n i ) 2 n i f_k(n)=\sum_{i=0}^n\binom nii^k \\=\sum_{i=0}^n\binom ni\sum_{j=0}^kS(k,j)\binom ijj!\\ =\sum_{i=0}^kS(k,i)i!\sum_{j=0}^n\binom nj\binom ji\\ =\sum_{i=0}^kS(k,i)i!\binom ni2^{n-i}
可以在 O ( k ) O(k) 时间内计算,其中 S ( k , i ) S(k,i) 为第二类斯特林数。
综上, f k ( n ) , S ( k , i ) , { a k } f_k(n),S(k,i),\{a_k\} 均可在 O ( k 2 ) O(k^2) 时间内求出。
(实际上,关于 f k ( n ) f_k(n) ,可以使用一些关于生成函数的技巧得知其是一个 O ( k ) O(k) 次多项式与 2 n 2^n 的乘积,可以使用拉格朗日插值在 O ( k 2 ) O(k^2) 时间内算出单项(所以说好像没啥用))
总之这样就做完了。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define mod 1000000007
#define lint long long
#define gc getchar()
#define N 310
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int st[N][N],fac[N],facinv[N],inv[N],a[N],npm[N],pm2[N],f[N];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
const int inv2=fast_pow(2,mod-2);
inline int prelude(int n)
{
	fac[0]=1;
	for(int i=1;i<=n;i++) fac[i]=(lint)fac[i-1]*i%mod;
	facinv[n]=fast_pow(fac[n],mod-2);
	for(int i=n-1;i>=0;i--) facinv[i]=(i+1ll)*facinv[i+1]%mod;
	for(int i=1;i<=n;i++) inv[i]=(lint)fac[i-1]*facinv[i]%mod;
	st[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=i;j++)
			st[i][j]=(st[i-1][j-1]+(lint)j*st[i-1][j])%mod;
	return 0;
}
inline int C(int n,int m)
{
	if(n<0||m<0||n<m) return 0;
	return (lint)fac[n]*facinv[m]%mod*facinv[n-m]%mod;
}
inline int get_ca(int k)
{
	memset(a,0,sizeof(int)*(k+1)),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]-(lint)i*a[j]%mod+mod)%mod;
	for(int i=0;i<=k;i++) a[i]=(lint)a[i]*facinv[k]%mod;
	return 0;
}
int main()
{
	prelude(N-1);	
	for(int T=inn();T;T--)
	{
		int n=inn(),m=inn(),k=inn();lint ans=0;get_ca(k);
//		for(int i=0;i<=k;i++) debug(i)sp,debug(a[i])ln;
		npm[0]=1;for(int i=1;i<=k;i++) npm[i]=(lint)npm[i-1]*(n+m)%mod;
		pm2[0]=1;for(int i=1;i<=k;i++) pm2[i]=(lint)pm2[i-1]*(mod-2)%mod;
//		for(int i=0;i<=k;i++) debug(i)sp,debug(npm[i])ln;
//		for(int i=0;i<=k;i++) debug(i)sp,debug(pm2[i])ln;
		for(int i=0,tm=fast_pow(2,m);i<=k;i++)
		{
			lint s=0;
			for(int j=0,cmj=1,tmmj=tm;j<=i;j++)
				s+=(lint)st[i][j]*fac[j]%mod*cmj%mod*tmmj%mod,
				cmj=(lint)cmj*(m-j)%mod*inv[j+1]%mod,tmmj=(lint)tmmj*inv2%mod;
			f[i]=(int)(s%mod);
		}
		for(int i=0;i<=k;i++)
		{
			lint s=0;
			for(int t=0;t<=i;t++)
				s+=(lint)C(i,t)*pm2[i-t]%mod*npm[t]%mod*f[i-t]%mod;
			ans+=a[i]*(s%mod)%mod;
		}
		printf("%lld\n",ans%mod);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82881987