题解 CF891E Lust
题意
你有 \(n\) 个数 \(a_1,a_2,\dots,a_n\),要进行 \(k\) 次操作,每次随机选择一个数 \(x\in[1,n]\),把 \(a_x\) 减一,并将答案增加除 \(a_x\) 外所有数的乘积。
求最终答案的期望,答案对 \(10^9+7\) 取模。
解法
对于任意两次相邻的操作,将其交换后对答案并不影响,因此最终答案和每次减 \(1\) 的 \(a_i\) 的顺序无关,只和每个 \(a_i\) 被减了多少有关。
设 \(a_i\) 最终减少了 \(b_i\),容易发现题目要求的即为 \(\prod_{i=1}^{n}a_i-\prod_{i=1}^{n}(a_i-b_i)\) 的期望,因此我们只需求出 \(Res=\prod_{i=1}^{n}(a_i-b_i)\) 的期望。
注意到 \(Res=E(\prod_{i=1}^{n}(a_i-b_i))=\dfrac{1}{n^k}\sum\dfrac{k!}{\prod_{i=1}^{n}b_i!}\prod_{i=1}^{n}(a_i-b_i)=\dfrac{k!}{n^k}\sum\prod_{i=1}^{n}\dfrac{a_i-b_i}{b_i!}\),这和指数生成函数的形式很像,因此我们考虑每一个 \(a_j\) 的指数生成函数 \(\hat{F}_j(x)=\sum_{i\ge0}\dfrac{a_j-i}{i!}x^i\),则 \(\dfrac{k!}{n^k}\sum\prod_{i=1}^{n}\dfrac{a_i-b_i}{b_i!}=\dfrac{k!}{n^k}[x^k]\prod_{i=1}^{n}\hat{F}_i(x)\)。
\(\hat{F}_j(x)=\sum_{i\ge0}\dfrac{a_j-i}{i!}x^i\)
\(=\sum_{i\ge0}{\dfrac{a_jx^i}{i!}}-\sum_{i\ge0}{\dfrac{ix^i}{i!}}\)
\(=\sum_{i\ge0}{\dfrac{a_jx^i}{i!}}-\sum_{i\ge1}{\dfrac{xx^{i-1}}{(i-1)!}}\)
\(=\sum_{i\ge0}{\dfrac{(a_j-x)x^i}{i!}}\)
\(=e^x(a_j-x)\)
所以 \(Res=\dfrac{k!}{n^k}[x^k]\prod_{i=1}^{n}e^x(a_j-x)\)
\(=\dfrac{k!}{n^k}[x^k]e^{nx}\prod_{i=1}^{n}(a_j-x)\)
\(=\dfrac{k!}{n^k}[x^k]\sum_{i\ge0}{\dfrac{n^i}{i!}}x^i\prod_{i=1}^{n}(a_j-x)\)
由于 \(n\le5000\),我们暴力展开 \(\prod_{i=1}^{n}(a_j-x)=\sum_{i=0}^{n}c_ix^i\)。
所以 \(Res=\dfrac{k!}{n^k}[x^k]\sum_{i\ge0}{\dfrac{n^i}{i!}}x^i\sum_{i=0}^{n}c_ix^i\)
\(=\dfrac{k!}{n^k}\sum_{i=0}^{\min(n,k)}\dfrac{c_in^{k-i}}{(k-i)!}\)
\(=c_0+\sum_{i=1}^{\min(n,k)}\dfrac{c_i\prod_{j=k-i+1}^{k}j}{n^i}\)
最终答案为 \(\prod_{i=1}^{n}a_i-Res=-\sum_{i=1}^{\min(n,k)}\dfrac{c_i\prod_{j=k-i+1}^{k}j}{n^i}\),时间复杂度 \(O(n^2)\)。
Code
#include<cstdio>
#define LL long long
#define mod 1000000007
int n,k,e;LL t,ans=0,res,inv,mul=1;
LL a[5002],c[5002]={};
inline int min(int x,int y)
{
return x<y? x:y;
}
inline LL pow(LL a,int b)
{
if(!b)return 1;
if(b==1)return a;
LL c=pow(a,(b>>1));
c=(c*c)%mod;
if(b&1)c=(c*a)%mod;
return c;
}
int main()
{
scanf("%d%d",&n,&k),e=min(n,k),t=inv=pow(n,mod-2),c[n]=1;
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
for(int j=n-i;j<n;++j)c[j]=(c[j+1]*a[i]-c[j])%mod;
c[n]=-c[n];
}
for(int i=1;i<=e;++i,t=(t*inv)%mod)
{
res=t;
for(int j=k-i+1;j<=k;++j)res=(res*j)%mod;
ans=(ans-c[i]*res)%mod;
}
printf("%lld",(ans+mod)%mod);
return 0;
}