CF891E Lust 题解
本文版权归 Azazel 与博客园共有,欢迎转载,但需保留此声明,并给出原文地址,谢谢合作。
原文地址:https://www.cnblogs.com/Azazel/p/15185109.html
(~~~~) 为什么会有正经题目叫这个名字并且文题无关
题意
(~~~~) 你有 (n) 个数 (a_1,a_2,dots,a_n) ,进行 (k) 次操作,每次等概率在 ([1,n]) 中选择一个数 (x) ,使得 (a_x-1) 并产生除 (a_x) 外其他数乘积的贡献。
题解
(~~~~) 首先发现产生贡献的式子很奇怪,对于某个 (x) ,其单次产生的贡献为 (prod_{i=1}^n [i ot= x] (a_i-b_i)) ,其中 (b_i) 表示在该操作之前 (i) 被选择过多少次。全局的贡献则还需要枚举 (k) 次 (x) 。
(~~~~) 这个式子并不优美,那么我们考虑把它换成优美的形式:
(~~~~) 这显然是正确的全局贡献,原因略过。
(~~~~) 那么我们就可以改为求 (E[prod_{i=1}^n a_i-prod_{i=1}^n (a_i-b_i)]) ,更具体地,我们应求出 (E[prod_{i=1}^n (a_i-b_i)])。
(~~~~) 对于任意已知的 ({b}) ,其产生的概率为 (dfrac{frac{k!}{prod_{i=1}^n b_i!}}{n^k}) ,即共有 (n^k) 种产生的 (x) 的序列,而有可重集的排列方案即为分子。故
(~~~~) 然后就是我不会的仙术了。
(~~~~) 对于后面一堆 (prod) ,我们使用生成函数进行计算。记: (f_i(x)=sum_{j=0}^{infty}(a_i-j)dfrac{x^j}{j!}) ,对生成函数化一波式子:
(~~~~) 然后代回式子:
(~~~~) 记最后 (prod_{i=1}^n (a_i-x)=sum_{i=0}^n c_ix^i) ,这可以 (n^2) 求得,并代回答案的式子:
(~~~~) 由于 (sum_{i=1}^n b_i=k) ,所以我们只需要 ([x^k]) 部分:
(~~~~) 可以求了!
代码
查看代码
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int MOD=1e9+7;
ll a[5005],b[5005],Pow[5005];
ll qpow(ll A,ll B)
{
ll ret=1;
while(B)
{
if(B&1) ret=ret*A%MOD;
B>>=1;A=A*A%MOD;
}
return ret;
}
int main() {
int n,k;ll Pro=1;
scanf("%d %d",&n,&k);
if(n==1)
{
printf("%d",k);
return 0;
}
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),Pro=Pro*a[i]%MOD;
b[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=i;j>=1;j--) b[j]=(b[j]*a[i]%MOD-b[j-1]+MOD)%MOD;
b[0]=b[0]*a[i]%MOD;
}
ll Fac=1,Ans=0;Pow[0]=1;
for(int i=1;i<=n;i++) Pow[i]=Pow[i-1]*n%MOD;
for(int i=0;i<=n;i++)
{
Ans=(Ans+b[i]*Fac%MOD*qpow(Pow[i],MOD-2)%MOD)%MOD;
Fac=Fac*(k-i)%MOD;
}
printf("%lld",(Pro-Ans+MOD)%MOD);
return 0;
}