题意概括
有 n n n 个糖果,每种都有一个颜色 c i c_i ci,求对于所有 k ∈ [ 1 , n ] k\in [1,n] k∈[1,n] ,求出 C n k C_n^k Cnk 种方案中糖果种类的期望数,对 998244353 998244353 998244353 取模。
分析
通过期望的定义,设 v i s i vis_i visi 表示每种颜色有没有被选,颜色总数为 m m m,则期望为 E ( ∑ j = 1 m v i s j ) E(\sum\limits_{j=1}^{m}vis_j) E(j=1∑mvisj),由线性期望的性质, E ( ∑ j = 1 m v i s j ) = ∑ j = 1 m E ( v i s j ) E(\sum\limits_{j=1}^{m}vis_j)=\sum\limits_{j=1}^{m}E(vis_j) E(j=1∑mvisj)=j=1∑mE(visj)。
因为一个颜色的期望为:出现的方案数/总方案数=(总方案数-未出现的方案数)/总方案数,设每种颜色的总数为 c n t j cnt_j cntj,所以 E ( v i s j ) = C n k − C n − c n t j k C n k E(vis_j)=\frac{C_{n}^{k}-C_{n-cnt_j}^{k}}{C_n^k} E(visj)=CnkCnk−Cn−cntjk。
可以把 c c c 数组离散化,再计算 c n t cnt cnt,因为 ∑ i = 1 m c n t i = n \sum\limits_{i=1}^{m}cnt_i=n i=1∑mcnti=n,可把式子转化成 m m a x ( m m a x + 1 ) = 2 n m_{max}(m_{max}+1)=2n mmax(mmax+1)=2n,所以 m m m 严格小于 n \sqrt n n,总时间复杂度在 O ( n n ) O(n\sqrt n) O(nn) 级别。
因为空间足够,且调用次数较多,预处理出 1 ∼ n 1\sim n 1∼n 的阶乘和逆元,用于 O ( 1 ) O(1) O(1) 求解组合数。
Code
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const ll mod=998244353;
ll n,m,c[50005],b[50005],col[50005],cnt[50005],jc[50005],inv[50005];
inline ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod,b>>=1;
}
return res;
}
inline void init(ll x){
jc[0]=1;
for(ll i=1;i<=x;++i){
jc[i]=jc[i-1]*i%mod;
}
inv[x]=qpow(jc[x],mod-2);
for(ll i=x-1;i>=0;--i)inv[i]=inv[i+1]*(i+1)%mod;
}
inline ll C(ll n,ll m){
if(m<0||n<m)return 0;
return jc[n]*inv[n-m]%mod*inv[m]%mod;
}
map<ll,ll>mp1,mp2;
signed main(){
cin>>n,init(n);
for(ll i=1;i<=n;++i)cin>>c[i],mp1[c[i]]++;
for(auto i:mp1)mp2[i.second]++;
for(auto i:mp2)c[++m]=i.first,cnt[m]=i.second;
for(ll i=1;i<=n;++i){
ll ans=0;
for(ll j=1;j<=m;++j){
ans=(ans+(C(n,i)-C(n-c[j],i)+mod)%mod*cnt[j]%mod)%mod;
}
ans=ans*qpow(C(n,i),mod-2)%mod;
cout<<ans<<'\n';
}
return 0;
}