1 条题解

  • 0
    @ 2025-8-24 22:07:27

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 离散小波变换°
    有志不在年高,无志空长百岁

    搬运于2025-08-24 22:07:27,当前版本为作者最后更新于2020-04-11 23:26:56,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目大意

    nn个数中选择kk个(可以重合),求这kk个数的乘积的期望。

    题解

    很显然,这个问题可以拆分为两部分:求方案总数,以及求所有方案的贡献和

    求方案总数

    我们设Fi,jF_{i,j}表示前ii个数中,选择jj个数的方案。那么考虑第ii个数如何处理。

    • 1.1.不选择第ii个数。它的方案总数为Fi1,jF_{i-1,j}

    • 2.2.选择第ii个数。它的方案总数为Fi,j1F_{i,j-1}

    那么有:

    Fi,j=Fi1,j+Fi,j1F_{i,j}=F_{i-1,j}+F_{i,j-1}

    求贡献和

    同样地,我们定义Gi,jG_{i,j}表示前ii个数中,选择jj个数的贡献总和。与上文类似,考虑第ii个数的情况。

    • 1.1.不选择第ii个数。这一部分的贡献总和为Gi1,jG_{i-1,j}

    • 2,2,选择第ii个数。这一部分的贡献总和为Gi,j1×AiG_{i,j-1}\times A_i

    也就是说,

    Gi,j=Gi1,j+Gi,j1×AiG_{i,j}=G_{i-1,j}+G_{i,j-1}\times A_i

    最后的答案为Gn,kFn,k\frac{G_{n,k}}{F_{n,k}}。用快速幂求出Fn,kF_{n,k}的逆元即可。

    空间优化

    O(n×k)\mathcal O(n\times k)的空间会爆炸。因此考虑滚动数组优化。

    Fi,x,Gi,xF_{i,x},G_{i,x}的值只和Fi1,xF_{i-1,x}Gi1,xG_{i-1,x}的值相关。因此我们只需要保留上一个枚举到的ii即可。具体的实现中,我们只需要用布尔变量oo表示当前所用的数组,而noto\operatorname{not} o表示上一个枚举到的ii时所用的数组。每次枚举完ii,就令onotoo\gets \operatorname{not} o即可。

    时间复杂度O(n×k)\mathcal O(n\times k),空间复杂度O(k)\mathcal O(k)

    参考代码

    #include<bits/stdc++.h>
    #define up(l,r,i) for(int i=l;i<=r;i++)
    #define dn(l,r,i) for(int i=l;i>=r;i--)
    using namespace std;
    
    typedef long long LL;
    const int INF =2147483647;
    int qread(){
        int w=1,c,ret;
        while((c=getchar())> '9'||c< '0')
        w=(c=='-'?-1:1); ret=c-'0';
        while((c=getchar())>='0'&&c<='9')
        ret=ret*10+c-'0';
        return ret*w;
    }
    const int MOD =19260817;
    const int MAXN =1e5+3,MAXK=300+3;
    int F[2][MAXK],G[2][MAXK],P[MAXN];
    int n,k; bool o;
    int pwr(int x,int y){
        int ret=1,t=x; while(y){
            if(y&1) ret=(LL)ret*t%MOD; y>>=1,t=(LL)t*t%MOD;
        }
        return ret;
    }
    int main(){
        n=qread(),k=qread(); up(1,n,i) P[i]=qread();
        F[!o][0]=1;
        up(1,n,i){
            F[o][0]=1; up(1,k,j)F[o][j]=(F[!o][j]+F[o][j-1])%MOD;
            G[o][0]=1; up(1,k,j)G[o][j]=((LL)G[!o][j]+(LL)G[o][j-1]*P[i])%MOD;
            o=!o;
        }
        printf("%d\n",(LL)G[!o][k]*pwr(F[!o][k],MOD-2)%MOD);
        return 0;
    }
    
    • 1

    信息

    ID
    4022
    时间
    1000ms
    内存
    125MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者