CF891E Lust 题解

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 \not= x] (a_i-b_i)\) ,其中 \(b_i\) 表示在该操作之前 \(i\) 被选择过多少次。全局的贡献则还需要枚举 \(k\)\(x\)

\(~~~~\) 这个式子并不优美,那么我们考虑把它换成优美的形式:

\[\large \prod_{i=1}^n a_i-\prod_{i=1}^n (a_i-b_i) \]

\(~~~~\) 这显然是正确的全局贡献,原因略过。

\(~~~~\) 那么我们就可以改为求 \(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\) 的序列,而有可重集的排列方案即为分子。故

\[\large E[\prod_{i=1}^n (a_i-b_i)]=\dfrac{\frac{k!}{\prod_{i=1}^n b_i!}}{n^k} \prod_{i=1}^n (a_i-b_i)=\dfrac{k!}{n^k}\prod_{i=1}^n\dfrac{a_i-b_i}{b_i!} \]

\(~~~~\) 然后就是我不会的仙术了。

\(~~~~\) 对于后面一堆 \(\prod\) ,我们使用生成函数进行计算。记: \(f_i(x)=\sum_{j=0}^{\infty}(a_i-j)\dfrac{x^j}{j!}\) ,对生成函数化一波式子:

\[\large f_i(x)=\sum_{j=0}^{\infty}\dfrac{x^j}{j!}a_i-\dfrac{x^{j-1}}{(j-1)!}x=e^x(a_i-x) \]

\(~~~~\) 然后代回式子:

\[\large \prod_{i=1}^n f_i(x)\\ \large =\prod_{i=1}^n e^x(a_i-x)\\ =\large e^{nx}\prod_{i=1}^n (a_i-x) \]

\(~~~~\) 记最后 \(\prod_{i=1}^n (a_i-x)=\sum_{i=0}^n c_ix^i\) ,这可以 \(n^2\) 求得,并代回答案的式子:

\[\large \dfrac{k!}{n^k} e^{nx}\sum_{i=0}^n c_ix^i\\ \large = \dfrac{k!}{n^k}\sum_{i=0}^nc_ix^i\sum_{j=0}^{\infty}\dfrac{n^j}{j!}x^j \]

\(~~~~\) 由于 \(\sum_{i=1}^n b_i=k\) ,所以我们只需要 \([x^k]\) 部分:

\[\large \dfrac{k!}{n^k} \sum_{i=0}^n c_i\dfrac{n^{k-i}}{(k-i)!}x^k\\ \large \sum_{i=0}^n c_i\dfrac{k!}{n^i(k-i)!} \]

\(~~~~\) 可以求了!

代码

查看代码
#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;
}
posted @ 2021-08-25 15:04  Azazеl  阅读(91)  评论(0编辑  收藏  举报