[CODECHEF]EASYEX

题意:有一个$k$面的骰子,上面的数字为$1\cdots k$,现在要丢$n$次骰子,设$n$次中有$a_i$次扔到数字$i$,给定$l,f$,求$\prod\limits_{i=1}^la_i^f$的期望,对$p=2003$取模

设$lf$个随机$0/1$变量$x_{i,j}$表示第$j$次的数字是否为$i$,那么每个变量都有$\frac1k$的概率为$1$,我们要求$\prod\limits_{i=1}^l\left(\sum\limits_{j=1}^nx_{i,j}\right)^f$的期望

如果把这个式子展开,最终的式子形如许多个$\prod x_{?,?}^?$之和,如果有一项同时含有$x_{a,j},x_{b,j}(a\neq b)$,那么它对答案的贡献为$0$,不妨对这些项按“含多少个不同的$x_{?,j}$”进行分类,最后再把每一类的结果加起来即可

设$f_{i,j}$表示在前$i$个$\left(\sum x_{?,?}\right)^f$中,选出$j$个不同的$x_{?,?}$的方案数(不考虑选的顺序),那么$f_{i,j}=\sum\limits_{k=1}^ff_{i-1,j-k}{f\brace k}$(在这$\left(\sum x_{?,?}\right)^f$中必须选$f$个$x_{?,?}$,去重后要得到$k$个不同的$x_{?,?}$,这样的方案与子集划分一一对应,考虑每个$x_{i,j}$第一次被选的位置和一个子集划分中每个子集的第一个元素即可得到它们是一一对应的)

设$g_i$表示最终选出来含$i$个不同的$x_{?,j}$的方案数,那么$g_i=[x^i]\left(\sum\limits_{i=1}^f{f\brace i}x^i\right)^l$,考虑顺序和概率后,答案就是$\sum\limits_{i=l}^{lf}n^\underline i\left(\frac1k\right)^ig_i$

因为答案中含下降幂,所以$i\geq p$的项都是$0$,于是算$g$只用暴力卷积到$p$位,总时间复杂度$O(p^2\log l)$

#include<stdio.h>
#include<string.h>
typedef long long ll;
const int mod=2003;
int pow(int a,int b){
	int s=1;
	while(b){
		if(b&1)(s*=a)%=mod;
		(a*=a)%=mod;
		b>>=1;
	}
	return s;
}
int S[1010][1010];
void pre(int n){
	int i,j;
	S[0][0]=1;
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++)S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%mod;
	}
}
struct poly{
	int x[mod];
	poly(){memset(x,0,sizeof(x));}
	int&operator[](int k){return x[k];}
};
ll t[mod];
poly operator*(poly a,poly b){
	int i,j;
	poly c;
	memset(t,0,sizeof(t));
	for(i=0;i<mod;i++){
		for(j=0;j<mod;j++){
			if(i+j<mod)t[i+j]+=a[i]*b[j];
		}
	}
	for(i=0;i<mod;i++)c[i]=t[i]%mod;
	return c;
}
poly pow(poly a,int b){
	poly s;
	s[0]=1;
	while(b){
		if(b&1)s=s*a;
		a=a*a;
		b>>=1;
	}
	return s;
}
poly p;
void work(){
	int n,k,l,f,i,s,d,t;
	scanf("%d%d%d%d",&n,&k,&l,&f);
	memset(p.x,0,sizeof(p.x));
	for(i=1;i<=f;i++)p[i]=S[f][i];
	p=pow(p,l);
	k=pow(k%mod,mod-2);
	s=0;
	d=1;
	t=pow(k,l);
	for(i=0;i<l;i++)(d*=(n-i)%mod)%=mod;
	for(i=l;i<=l*f&&d;i++){
		(s+=(ll)d*t*p[i]%mod)%=mod;
		(d*=(n-i)%mod)%=mod;
		(t*=k)%=mod;
	}
	printf("%d\n",s);
}
int main(){
	int T;
	pre(1000);
	scanf("%d",&T);
	while(T--)work();
}
posted @ 2018-11-23 09:29 jefflyy 阅读(...) 评论(...) 编辑 收藏