CF891E,奇妙的计数题

本文介绍了一道关于期望乘积差的题目,通过巧妙的DP算法优化,从O(nk^2)降低到了O(n^2),并详细解析了优化过程及实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面传送门
题解
首先这道题面里的”res”,其实就是初始n个数的积与k次操作后的期望乘积之差。这个挺显然的,然而我一开始就没往这方面去想,反倒想出了什么倒数和的期望,我好菜啊。
知道这个性质后,我想出了一个 O(nk2) 的DP
然后就是题解里的算法,最后居然是 O(n2)
我仔细看了一下,感觉题解这么优越,是因为不必枚举每个数减了记下,dp时每次在k这一维上的偏移量都是1,是常量,比我少一个k。同时题解里又发现dp的过程实质上就是在n维空间(每一维大小都是2)里行走的方案数,所以可以使用组合数,又比我少一个k,挺奇妙的。
好像有人说这很简单?看来还是我太弱了。

#include<cstdio>
const int N=5005,mo=1000000007;
int n,k,f[N][N],i,j,a,ans,inv[N],l;
inline int pow(int a,int b){
    int ans=1;
    for(;b;b>>=1,a=1ll*a*a%mo)if(b&1)ans=1ll*ans*a%mo;return ans;
}
inline int P(int a,int b){
    int ans=1,i;
    for(i=1;i<=b;++i)ans=1ll*ans*(a-i+1)%mo;
    return ans;
}
int main(){
    scanf("%d%d",&n,&k);
    for(i=2,inv[1]=1;i<=n;++i)inv[i]=1ll*(mo-mo/i)*inv[mo%i]%mo;**f=1;
    for(i=1;i<=n;++i){
        scanf("%d",&a);
        for(j=*f[i]=1;j<=i;++j)f[i][j]=(f[i-1][j]+1ll*f[i-1][j-1]*a)%mo;
    }
    for(i=j=1,l=inv[n];i<=n && i<=k;++i,j=-j,l=1ll*l*inv[n]%mo)
        ans=(ans+mo+1ll*j*P(k,i)*l%mo*f[n][n-i]%mo)%mo;
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值