正题
题目链接:https://www.luogu.com.cn/problem/CF891E
题目大意
nnn个数字的一个序列aia_iai,每次随机选择一个让它减去一。然后贡献加上所有其他aia_iai的乘积。
执行kkk次,求贡献答案。
1≤n≤5000,0≤ai,k≤1091\leq n\leq 5000,0\leq a_i,k\leq 10^91≤n≤5000,0≤ai,k≤109
解题思路
这个操作很麻烦,但是其实答案就是开始时所有aia_iai的乘积减去结束时所有aia_iai的乘积。
设第iii个数减去了bib_ibi次,就是求∏i=1nai−∏i=1n(ai−bi)\prod_{i=1}^na_i-\prod_{i=1}^n(a_i-b_i)∏i=1nai−∏i=1n(ai−bi)的期望,考虑怎么求后面那个东西。
推一下式子不难发现对于一组bib_ibi对期望的贡献就是
1nkk!∏i=1n(bi!)∏i=1n(ai−bi)\frac{1}{n^k}\frac{k!}{\prod_{i=1}^n(b_i!)}\prod_{i=1}^n(a_i-b_i)nk1∏i=1n(bi!)k!i=1∏n(ai−bi)
(总方案×可重排方案×贡献)
把∏i=1n(bi!)\prod_{i=1}^n(b_i!)∏i=1n(bi!)丢进去会有很神奇的结果
⇒k!nk∏i=1nai−bibi!\Rightarrow \frac{k!}{n^k}\prod_{i=1}^n\frac{a_i-b_i}{b_i!}⇒nkk!i=1∏nbi!ai−bi
因为每种方案都要求和,后面那个东西显然可以生成函数搞,设
fz^(x)=∑i=0n(az−i)xii!=∑i=0∞azxii!−∑i=0∞ixii!\widehat{f_z}(x)=\sum_{i=0}^n(a_z-i)\frac{x^i}{i!}=\sum_{i=0}^\infty a_z\frac{x^i}{i!}-\sum_{i=0}^\infty i\frac{x^i}{i!}fz(x)=i=0∑n(az−i)i!xi=i=0∑∞azi!xi−i=0∑∞ii!xi
好像就搞不动了,前面那个是azexa_ze^{x}azex,其实后面那个把iii抵消掉阶乘就是xexxe^{x}xex
fz(x)^=(az−x)ex\widehat{f_z(x)}=(a_z-x)e^xfz(x)=(az−x)ex
然后F^=∏i=1nfz^\widehat{F}=\prod_{i=1}^n\widehat{f_z}F=∏i=1nfz,可以暴力O(n2)O(n^2)O(n2)乘出∏i=1n(az−x)\prod_{i=1}^n(a_z-x)∏i=1n(az−x)这部分,记为∑i=0∞cixi\sum_{i=0}^{\infty}c_ix^i∑i=0∞cixi。
然后展开后面的exe^xex就有
F(x)^[xk]=∑i=0kcink−i(k−i)!\widehat{F(x)}[x^k]=\sum_{i=0}^kc_{i}\frac{n^{k-i}}{(k-i)!}F(x)[xk]=i=0∑kci(k−i)!nk−i
然后
ans=∑i=0kcik!(k−i)!nians=\sum_{i=0}^kc_{i}\frac{k!}{(k-i)!n^i}ans=i=0∑kci(k−i)!nik!
就好了,时间复杂度O(n2)O(n^2)O(n2)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=5100,P=1e9+7;
ll n,k,f[N],ans;
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%P;x=x*x%P;b>>=1;}return ans;
}
signed main()
{scanf("%lld%lld",&n,&k);f[0]=1;for(ll i=1;i<=n;i++){ll x;scanf("%lld",&x);for(ll j=i;j>=1;j--)f[j]=(f[j]*x-f[j-1]+P)%P;f[0]=f[0]*x%P;}ll tt=1,inv=power(n,P-2);for(ll i=0;i<=n;i++){ans=(ans+f[i]*tt%P)%P;tt=tt*inv%P*(k-i)%P;}printf("%lld\n",(f[0]-ans+P)%P);return 0;
}