你有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 1≤n≤5000,1≤k≤109,0≤ai≤109
我们考虑在某一个局面即将进行一次操作:
记现在 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∏(ai−bi),同时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) ((ax−bx)−(ax−(bx+1)))∗i!=x∏(ai−bi)
∏ 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=1∏n(ai−bi)−(i=1∏n(ai−bi))∗(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=1∏n(ai−bi)
那么一次的贡献为: 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=1∏nai
于是类似于裂项相消的样子,我们只剩初局面和末局面
即
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)−∑nk∗∏i=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!} ∑nk∗∏i=1nbi!k!∗i=1∏(ai−bi)=nkk!∗∑i=1∏bi!ai−bi
发现这个似乎很难搞,我们考虑化简和指数型母函数构造:
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=1∏nj=0∑+∞j!ai−jxj
= ∏ 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=1∏nj=0∑+∞(j!aixj−j!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=1∏n(j=0∑+∞j!aixj−j=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=1∏n((ai−x)∗j=0∑+∞j!xj)
= ∏ i = 1 n ( ( a i − x ) ∗ e x ) =\prod_{i=1}^n((a_i-x)*e^x) =i=1∏n((ai−x)∗ex)
= e n x ∏ i = 1 n ( a i − x ) =e^{nx}\prod_{i=1}^n(a_i-x) =enxi=1∏n(ai−x)
我们的目标是求 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)=enx∗i=0∑nci∗xi
前面拆开:
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=0∑nci∗xi
我们要求第 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=0∑nci∗(k−i)!nk−i
回代到答案的后半段:
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=1∏bi!ai−bi=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=0∑nci∗(k−i)!nk−i
我们知道 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=0∑nci∗niAki
最后这个式子我们可以考虑递推 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;
}