【20联赛集训day8】高考考

【20联赛集训day8】高考考

芝士:概率分析、min-max 容斥、组合数学、推柿子。

有一个长度为 \(n\) 的初始全部是 \(1\) 的序列,要求做 \(m\) 次操作,每次操作随机选择一个数字将它加 \(1\),选到第 \(i\) 个数字的概率为 \(\frac{a_i}{\sum_{j=1}^{n} a_j}\)

考虑最终形成的序列,我们可以发现形成每种序列的概率是一样的,证明:生成一个序列 \(A\) 的概率为:

\[\frac{\prod(a_i-1)!}{\frac{(n+m-1)!}{(n-1)!}}\cdot \frac{m!}{\prod{(a_i-1)!}}=\frac{1}{\binom{n+m-1}{n-1}}=\frac{(n-1)!m!}{(n+m-1)!} \]

求前 \(k\) 大的数的期望可以转化为求第 \(k\) 大的数期望。

由于第 \(k\) 大的数的期望不好求,我们可以用 min-max 容斥转化为求所有集合的最小值的期望。

\[E(kthmax\{S\})=\sum_{T\subseteq S} (-1)^{|T|-k}\binom{|T|-1}{k-1}E(\min_{j\in T} x_j) \]

求一个 \(s\) 集合最小的数就是求集合第 \(|s|\) 大的数。

\(f_i\) 表示含有 \(i\) 个数的集合中,第 \(i\) 大的数的期望,然而这不好算。我们容易算出第 \(i\) 大的数大于等于 \(j\) 的方案数,即集合所有数都 \(\ge j\) 的方案数。用插板法。先预先抽走 \(i(j-1)\) 个空,然后插上 \(n-1\) 个板把全局分成 \(n\) 个部分,最后把集合的部分放回那些板就能保证集合 \(\ge j\)

\[f_{i,j}=\binom{n+m-1-i(j-1)}{n-1} \]

\[f_i=\sum_{j=1}^{n+m} f_{i,j} \]

这个式子表示集合最小的数 \(\ge j\) 的方案数总和,\(\ge j\) 的方案数会被 $\ge 1\sim j $ 都算一次,一共 \(j\) 次,这样一个 \(\ge j\) 的方案对答案的贡献就是 \(j\) 了。因此可以表示长度为 \(i\) 的集合最小的数的期望。

那么我们现在已经求出了长度为 \(i\) 的集合最小的数的期望,把它带进 min-max 容斥公式里可以得到(\(g_j=k\) 表示全局第 \(k\) 大的数的期望):

\[g_k=\sum_{i} (-1)^{i-k} \binom{i-1}{k-1} f_i\binom{n}{i} \]

还要乘上 \(\binom{n}{i}\) 的原因是有这么多种长度为 \(i\) 的集合。

\[ans_k=\sum_{i\le k} g_i \]

答案很显然。

Code

#include<bits/stdc++.h>
#define sf scanf
#define pf printf
// #define DEBUG
#define rep(x,y,z) for(int x=(y);x<=(z);x++)
#define isdigit(x) (x>='0'&&x<='9')
using namespace std;
typedef long long ll;
const int N=5e3+5,mod=1e9+7,NN=1e4;
int n,m;
ll jc[N<<1];
ll inv[N<<1];
ll ksm(ll a,ll b){
    ll s=1;
    while(b){
        if(b&1) s=s*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return s;
}
void init(){
    jc[0]=1;
    rep(i,1,NN) jc[i]=jc[i-1]*i%mod;
    inv[NN]=ksm(jc[NN],mod-2);
    for(int i=NN-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
ll sub(ll a,ll b){return ((a-b)%mod+mod)%mod;}
ll add(ll a,ll b){return (a+b)%mod;}
ll f[N],g[N];
ll comb(ll n,ll m){
    if(n<m) return 0;
    return jc[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
    #ifdef DEBUG
    freopen("in.txt","r",stdin);
    freopen("my.out","w",stdout);
    #endif
    sf("%d%d",&n,&m);
    init();
    rep(i,1,n){
        for(int j=0;j<=m;j++){
            f[i]=add(f[i],comb(n+m-1-i*j,n-1));
        }
    }
    rep(k,1,n){
        rep(i,k,n){
            ll t=f[i]*comb(i-1,k-1)%mod*comb(n,i)%mod;
            if((i-k)&1) g[k]=sub(g[k],t);
            else g[k]=add(g[k],t);
        }
    }
    rep(i,2,n) g[i]=add(g[i],g[i-1]);
    rep(i,1,n) g[i]=g[i]*jc[n-1]%mod*jc[m]%mod*inv[n+m-1]%mod,pf("%lld\n",g[i]);
}
posted @ 2024-09-27 13:49  liyixin  阅读(3)  评论(0编辑  收藏  举报