题解:AT_arc217_c [ARC217C] Greedy Customers 2

思路

每个顾客选比自己小的最大商品可以直接等价于选比自己小的任意商品,然后最大化选的商品个数。

然后就相当于每个顾客向比自己小的商品连边,做二分图最大匹配。考虑 Hall 定理,只要把 \(\max\{|S|-N(S)\}\) 记到状态里就可以统计答案。于是直接统计 \(dp_{i,j,k}\) 表示考虑前 \(i\) 件商品,有 \(j\) 个顾客小于第 \(i+1\) 件商品,此时无法选择的顾客数量最大值为 \(k\) 时的概率。

然后转移分讨当前的 \(|S|-N(S)\) 是不是当前最大值就好了。复杂度 \(\mathcal O(n^4)\)

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int N=1e2+2,mod=998244353;
int n,c,invc,a[N],t[N],C[N][N],s[N],dp[N][N][N];
long long qpow(long long x,int y=mod-2){
    int ans=1;
    for(;y;y>>=1,x=x*x%mod)if(y&1)ans=ans*x%mod;
    return ans;
}
void solve(){
    memset(s,0,sizeof(s)),memset(dp,0,sizeof(dp));
    cin>>n>>c,invc=qpow(c);
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=C[0][0]=1;i<=n;i++)for(int j=0;j<=n;j++)C[i][j]=C[i-1][j-1]+C[i-1][j],C[i][j]>=mod&&(C[i][j]-=mod);
    memcpy(t,a,sizeof(t)),sort(t+1,t+n+1);
    int len=unique(t+1,t+n+1)-t-1;
    for(int i=1;i<=n;i++)s[lower_bound(t+1,t+len+1,a[i])-t]++;
    for(int i=1;i<=len;i++)s[i]+=s[i-1];
    for(int i=0;i<=n;i++)dp[0][i][i]=C[n][i]*qpow(1ll*(t[1]-1)*invc%mod,i)%mod;
    t[len+1]=c+1;
    for(int i=1;i<=len;i++){
        for(int j=0;j<=n;j++){
            for(int k=0;k<=j;k++){
                int d=max(0,j-s[i]),p=C[n-k][j-k]*qpow(1ll*(t[i+1]-t[i])*invc%mod,j-k)%mod;
                for(int l=0;l<=d;l++)dp[i][j][d]=(dp[i][j][d]+1ll*dp[i-1][k][l]*p)%mod;
                for(int l=d+1;l<=n;l++)dp[i][j][l]=(dp[i][j][l]+1ll*dp[i-1][k][l]*p)%mod;
            }
        }
    }
    for(int i=0;i<=n;i++)cout<<dp[len][n][n-i]<<' ';cout<<'\n';
}
signed main(){
    clock_t _st=clock();
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int t;cin>>t;
    while(t--)solve();
    clock_t _ed=clock();
    cerr<<(_ed-_st)*1.0/CLOCKS_PER_SEC<<'\n';
    return 0;
}
posted @ 2026-04-23 11:42  Redolent  阅读(4)  评论(0)    收藏  举报