CF891E,奇妙的计数题

题面传送门
题解
首先这道题面里的”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;
}

猜你喜欢

转载自blog.csdn.net/zxin__/article/details/78573534