• 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 ot= 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}^ndfrac{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^isum_{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_idfrac{n^{k-i}}{(k-i)!}x^k\ large sum_{i=0}^n c_idfrac{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;
    }
    
  • 相关阅读:
    345. Reverse Vowels of a String
    344. Reverse String
    125. Valid Palindrome
    67. Add Binary
    28. Implement strStr()
    20. Valid Parentheses
    14. Longest Common Prefix
    670. Maximum Swap
    2017济南北大青鸟accp和学士后课程的真实情况
    2017济南北大青鸟accp和学士后课程的真实情况
  • 原文地址:https://www.cnblogs.com/Azazel/p/15185109.html
Copyright © 2020-2023  润新知