Lust(Codeforces Round #446 Div.1-891E)(母函数\生成函数)

文章目录

  • 题目
  • 思路
  • 代码

题目

你有n个数 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an ,要进行 k k k 次操作,每次在 1 1 1 ~ n n n 中随机选择一个数 x x x,使得 r e s + = ∏ i ! = x a i res+=\prod_{i!= x}a_i res+=i!=xai ,然后 a x a_x ax 减少 1 1 1,求最后 r e s res res 值的期望,答案对 1 0 9 + 7 10^9+7 109+7 取模。
数据范围:
1 ≤ n ≤ 5000 , 1 ≤ k ≤ 1 0 9 , 0 ≤ a i ≤ 1 0 9 1\le n\le 5000,1\le k \le 10^9,0\le a_i\le 10^9 1n5000,1k109,0ai109

思路

我们考虑在某一个局面即将进行一次操作:
记现在 a i a_i ai 减少的次数为 b i b_i bi ,我们选中 a x a_x ax
那我们计算一次答案贡献:
∏ i ! = x ( a i − b i ) , 同 时 b x + = 1 \prod_{i!=x}(a_i-b_i),同时b_x+=1 i!=x(aibi),bx+=1
那么我们变形
( ( a x − b x ) − ( a x − ( b x + 1 ) ) ) ∗ ∏ i ! = x ( a i − b i ) ((a_x-b_x)-(a_x-(b_x+1)))*\prod_{i!=x}(a_i-b_i) ((axbx)(ax(bx+1)))i!=x(aibi)
∏ i = 1 n ( a i − b i ) − ( ∏ i = 1 n ( a i − b i ) ) ∗ ( a x − ( b x + 1 ) ) \prod_{i=1}^n(a_i-b_i)-(\prod_{i=1}^n(a_i-b_i))*(a_x-(b_x+1)) i=1n(aibi)(i=1n(aibi))(ax(bx+1))
我们记某一个局面 α = ( b 1 , b 2 , . . . , b n ) \alpha=(b_1,b_2,...,b_n) α=(b1,b2,...,bn)
我们记 f ( α ) = ∏ i = 1 n ( a i − b i ) f(\alpha)=\prod_{i=1}^n(a_i-b_i) f(α)=i=1n(aibi)
那么一次的贡献为: f ( α ) − f ( β ) f(\alpha)-f(\beta) f(α)f(β)
初局面:
f ( s t a r t ) = ∏ i = 1 n a i f(start)=\prod_{i=1}^na_i f(start)=i=1nai
于是类似于裂项相消的样子,我们只剩初局面和末局面


E = f ( s t a r t ) − ∑ k ! n k ∗ ∏ i = 1 n b i ! ∗ f ( e n d ) E=f(start)-\sum\frac{k!}{n^k*\prod_{i=1}^nb_i!}* f(end) E=f(start)nki=1nbi!k!f(end)
于是我们只需保证: ∑ i = 1 n b i = k \sum_{i=1}^nb_i=k i=1nbi=k
化简后半段
∑ k ! n k ∗ ∏ i = 1 n b i ! ∗ ∏ i = 1 ( a i − b i ) = k ! n k ∗ ∑ ∏ i = 1 a i − b i b i ! \sum\frac{k!}{n^k*\prod_{i=1}^nb_i!}*\prod_{i=1}(a_i-b_i)=\frac{k!}{n^k}*\sum\prod_{i=1}\frac{a_i-b_i}{b_i!} nki=1nbi!k!i=1(aibi)=nkk!i=1bi!aibi
发现这个似乎很难搞,我们考虑化简和指数型母函数构造:
G ( x ) = ∏ i = 1 n ∑ j = 0 + ∞ a i − j j ! x j G(x)=\prod_{i=1}^n\sum_{j=0}^{+\infty}\frac{a_i-j}{j!}x^j G(x)=i=1nj=0+j!aijxj
= ∏ i = 1 n ∑ j = 0 + ∞ ( a i j ! x j − j j ! x j ) =\prod_{i=1}^n\sum_{j=0}^{+\infty}(\frac{a_i}{j!}x^j-\frac{j}{j!}x^j) =i=1nj=0+(j!aixjj!jxj)
= ∏ i = 1 n ( ∑ j = 0 + ∞ a i j ! x j − ∑ j = 0 + ∞ x j ! x j ) =\prod_{i=1}^n(\sum_{j=0}^{+\infty}\frac{a_i}{j!}x^j-\sum_{j=0}^{+\infty}\frac{x}{j!}x^j) =i=1n(j=0+j!aixjj=0+j!xxj)
= ∏ i = 1 n ( ( a i − x ) ∗ ∑ j = 0 + ∞ x j j ! ) =\prod_{i=1}^n((a_i-x)*\sum_{j=0}^{+\infty}\frac{x^j}{j!}) =i=1n((aix)j=0+j!xj)
= ∏ i = 1 n ( ( a i − x ) ∗ e x ) =\prod_{i=1}^n((a_i-x)*e^x) =i=1n((aix)ex)
= e n x ∏ i = 1 n ( a i − x ) =e^{nx}\prod_{i=1}^n(a_i-x) =enxi=1n(aix)
我们的目标是求 G ( x ) G(x) G(x) 的第 k k k 项系数 f k f_k fk,考虑将后面直接 O ( n 2 ) O(n^2) O(n2) 拆成多项式形式(当然你会分治FFT O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)):
G ( x ) = e n x ∗ ∑ i = 0 n c i ∗ x i G(x)=e^{nx}*\sum_{i=0}^nc_i*x^i G(x)=enxi=0ncixi
前面拆开:
G ( x ) = ( 1 + n x 1 ! + ( n x ) 2 2 ! + . . . ) ∗ ∑ i = 0 n c i ∗ x i G(x)=(1+\frac{nx}{1!}+\frac{(nx)^2}{2!}+...)*\sum_{i=0}^nc_i*x^i G(x)=(1+1!nx+2!(nx)2+...)i=0ncixi
我们要求第 k k k 项的系数 g k g_k gk
g k = ∑ i = 0 n c i ∗ n k − i ( k − i ) ! g_k=\sum_{i=0}^nc_i*\frac{n^{k-i}}{(k-i)!} gk=i=0nci(ki)!nki
回代到答案的后半段:
k ! n k ∗ ∑ ∏ i = 1 a i − b i b i ! = k ! n k ∗ g k \frac{k!}{n^k}*\sum\prod_{i=1}\frac{a_i-b_i}{b_i!}=\frac{k!}{n^k}*g_k nkk!i=1bi!aibi=nkk!gk
= k ! n k ∗ ∑ i = 0 n c i ∗ n k − i ( k − i ) ! =\frac{k!}{n^k}*\sum_{i=0}^nc_i*\frac{n^{k-i}}{(k-i)!} =nkk!i=0nci(ki)!nki
我们知道 n n n 相较于 k k k 很小 于是继续化简:
= ∑ i = 0 n c i ∗ A k i n i =\sum_{i=0}^nc_i*\frac{A_k^i}{n^i} =i=0nciniAki
最后这个式子我们可以考虑递推 O ( n ) O(n) O(n) 计算
总时间复杂度: O ( n 2 ) / O ( n l o g 2 n ) O(n^2)/O(nlog^2n) O(n2)/O(nlog2n)

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
#define ULL unsigned long long
LL read(){
	LL f=1,x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return f*x;
}
#define MAXN 5000
#define INF 0x3f3f3f3f
#define Mod (LL)(1e9+7)
LL Pow(LL x,LL y){
	LL ret=1;
	while(y){
		if(y&1) ret=ret*x%Mod;
		x=x*x%Mod;
		y>>=1;
	}
	return ret;
}
LL a[MAXN+5],b[MAXN+5],c[MAXN+5];
int main(){
	LL n=read(),k=read(),ans=1;
	for(int i=1;i<=n;i++)
		a[i]=read(),ans=ans*a[i]%Mod;
	c[0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<i;j++)
			b[j]=c[j]*a[i]%Mod;
		for(int j=0;j<i;j++)
			b[j+1]=(b[j+1]-c[j]+Mod)%Mod;
		memcpy(c,b,sizeof(c));
	}
	LL f=0,t1=1,t2=1,invn=Pow(n,Mod-2);
	for(int i=0;i<=n;i++){
		f=(f+c[i]*t1%Mod*t2%Mod)%Mod;
		t1=t1*(k-i)%Mod,t2=t2*invn%Mod;
	}
	ans=(ans-f)%Mod;
	printf("%lld\n",(ans+Mod)%Mod);
	return 0;
}

你可能感兴趣的:(数学,生成函数\母函数,概率期望,CodeForces,计数,排列组合)