• 【CF891E】Lust(生成函数)


    点此看题面

    • 给定一个长度为(n)的序列(a),进行(k)次操作。
    • 每次操作随机选中一个(i),将(a_i)(1),收益为除它以外所有数的乘积,求期望收益。
    • (nle5 imes10^3,kle10^9)

    重要转化

    (a_i)(1)后,除它以外所有数的乘积恰好是(prod_{i=1}^na_i)的变化量。

    所以说,答案实际上就是原本的(prod_{i=1}^na_i)减去修改后(prod_{i=1}^na_i')的期望值。

    从动态规划到生成函数

    考虑暴力(DP),设(f_{i,j})表示前(i)个数一共修改了(j)次的所有方案下乘积之和。

    转移就是枚举当前位置修改了多少次,得到:

    [f_{i,p+q}=sum C_{p+q}^p imes (a_i-p) imes f_{i-1,q} ]

    经典暴拆组合数:

    [frac{f_{i,p+q}}{(p+q)!}=sumfrac{a_i-p}{p!} imesfrac{f_{i-1,q}}{q!} ]

    (F_i(x)=sum_{p=0}^{+infty}f_{i,p}frac{x^p}{p!},G_i(x)=sum_{p=0}^{+infty}(a_i-p)frac{x^p}{p!}),得到:

    [F_i(x)=F_{i-1}(x)*G_i(x) ]

    因此只要把(G_{1sim n}(x))(n)个生成函数卷起来就能得到(F_n(x)),而它的(k)次项系数就是(frac{f_{n,k}}{k!})了。

    推式子

    对于(G_i(x)),我们把(a_i-p)分开来:

    [G_i(x)=a_isum_{p=0}^{+infty}frac{x^p}{p!}-sum_{p=0}^{+infty}frac{x^{p+1}}{p!}=(a_i-x)e^x ]

    (A_i(x)=a_i-x),发现(F_n(x))就是(A_{1sim n}(x))(n)个生成函数卷起来之后再卷上(e^{nx})

    很容易(O(n^2))暴力求出(A_{1sim n}(x))卷起来后每一项的系数(f_i),于是:

    [F_n(x)=(sum_{i=0}^{+infty}f_ix^i)*(sum_{i=0}^{+infty}frac {(nx)^i}{i!})\ [x^k]F_n(x)=sum_{i=0}^kf_i imesfrac{n^{k-i}}{(k-i)!} ]

    乘上一个(k!)得到了总和(f_{n,k}),再除以总方案数(n^k)得到期望:

    [E=sum_{i=0}^{k}frac{f_i imes k^{underline i}}{n^i} ]

    最终答案就是(prod_{i=1}^na_i-E)

    代码:(O(n^2))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 5000
    #define X 1000000007
    using namespace std;
    int n,k,a[N+5],f[N+5];
    I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    int main()
    {
    	RI i,j;for(scanf("%d%d",&n,&k),f[0]=i=1;i<=n;++i) for(scanf("%d",a+i),j=i;~j;--j) f[j]=(1LL*a[i]*f[j]+(j?X-f[j-1]:0))%X;//暴力DP求系数
    	RI t=0,Iv=QP(n,X-2),g=1,p=1;for(i=0;i<=min(n,k);++i) t=(t+1LL*f[i]*g%X*p)%X,g=1LL*g*(k-i)%X,p=1LL*p*Iv%X;//计算答案
    	RI s=1;for(i=1;i<=n;++i) s=1LL*s*a[i]%X;return printf("%d
    ",(s-t+X)%X),0;//原乘积-修改后乘积期望值
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    sql增删改查-转载
    委托和事件 链接
    三层架构-转载
    ToList()方法
    Invoke--转载
    C# 6.0新特性---语法糖
    索引器
    HBase学习总结(1)
    教程-关于Owner和Parent的区别
    问题-在TreeView使用时,发现选中的树节点会闪烁或消失
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF891E.html
Copyright © 2020-2023  润新知