【20联赛集训day8】高考考
【20联赛集训day8】高考考
芝士:概率分析、min-max 容斥、组合数学、推柿子。
有一个长度为 \(n\) 的初始全部是 \(1\) 的序列,要求做 \(m\) 次操作,每次操作随机选择一个数字将它加 \(1\),选到第 \(i\) 个数字的概率为 \(\frac{a_i}{\sum_{j=1}^{n} a_j}\)。
考虑最终形成的序列,我们可以发现形成每种序列的概率是一样的,证明:生成一个序列 \(A\) 的概率为:
求前 \(k\) 大的数的期望可以转化为求第 \(k\) 大的数期望。
由于第 \(k\) 大的数的期望不好求,我们可以用 min-max 容斥转化为求所有集合的最小值的期望。
求一个 \(s\) 集合最小的数就是求集合第 \(|s|\) 大的数。
设 \(f_i\) 表示含有 \(i\) 个数的集合中,第 \(i\) 大的数的期望,然而这不好算。我们容易算出第 \(i\) 大的数大于等于 \(j\) 的方案数,即集合所有数都 \(\ge j\) 的方案数。用插板法。先预先抽走 \(i(j-1)\) 个空,然后插上 \(n-1\) 个板把全局分成 \(n\) 个部分,最后把集合的部分放回那些板就能保证集合 \(\ge j\)。
这个式子表示集合最小的数 \(\ge j\) 的方案数总和,\(\ge j\) 的方案数会被 $\ge 1\sim j $ 都算一次,一共 \(j\) 次,这样一个 \(\ge j\) 的方案对答案的贡献就是 \(j\) 了。因此可以表示长度为 \(i\) 的集合最小的数的期望。
那么我们现在已经求出了长度为 \(i\) 的集合最小的数的期望,把它带进 min-max 容斥公式里可以得到(\(g_j=k\) 表示全局第 \(k\) 大的数的期望):
还要乘上 \(\binom{n}{i}\) 的原因是有这么多种长度为 \(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]);
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18435534