「ABC215G」 Colorful Candies 2

文章描述了一个问题,如何计算n个不同颜色糖果中,每种颜色被选中的期望数量,对998244353取模。通过离散化颜色总数并利用组合数公式和线性期望的性质,优化了时间复杂度至O(n√n),并提及了预处理阶乘和逆元以提高效率。

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

题意概括

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=1mvisj),由线性期望的性质, 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=1mvisj)=j=1mE(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)=CnkCnkCncntjk

可以把 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=1mcnti=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 1n 的阶乘和逆元,用于 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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值