codeforces1156F. Card Bag

链接

https://codeforces.com/problemset/problem/1156/F

题解

排个序然后把相同的合并下, a i a_i ai表示大小为 i i i的数有多少个
f i j f_{ij} fij表示前 i i i种数,选出 j j j个严格递增的,概率是多少
f i j = f i − 1 , j + f i − 1 , j − 1 a i n − j + 1 f_{ij}=f_{i-1,j}+f_{i-1,j-1}\frac{a_i}{n-j+1} fij=fi1,j+fi1,j1nj+1ai
统计答案就枚举最后两个是谁然后求一下和就好了

题外话

这种概率 d p dp dp裸题放在 F F F真的没问题??
这题比 B 、 C B、C BC简单多了好嘛qwq
B B B题硬是自闭到最后
什么玩意,出题人有毒吧qwq

代码

#include 
#define maxn 5050
#define mod 998244353ll
using namespace std;
typedef long long ll;
ll f[maxn][maxn], N, a[maxn], inv[maxn], s[maxn], tmp[maxn];
ll read(ll x=0)
{
    ll c, f=1;
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-48;
    return f*x;
}
void init()
{
    ll i;
    inv[1]=1;
    for(i=2;i<maxn;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;
    N=read();
    for(i=1;i<=N;i++)tmp[read()]++;
    auto x(0);
    for(i=1;i<=N;i++)if(tmp[i])a[++x]=tmp[i];
    N=x;
    for(i=1;i<=N;i++)s[i]=s[i-1]+a[i];
}
void dp()
{
    ll i, j;
    for(i=0;i<maxn;i++)f[i][0]=1;
    for(i=1;i<=N;i++)
    {
        for(j=1;j<=i;j++)
        {
            f[i][j]=f[i-1][j] + f[i-1][j-1]*a[i]%mod*inv[s[N]-j+1];
            f[i][j]%=mod;
        }
    }
}
int main()
{
    init();
    dp();
    ll i, j, ans(0);
    for(i=1;i<=N;i++)for(j=0;j<=i-1;j++)
    {
        ans+=f[i-1][j] * (a[i]*(a[i]-1)%mod) %mod * (inv[s[N]-j]*inv[s[N]-j-1]%mod);
        ans%=mod;
    }
    printf("%lld",ans);
    return 0;
}

你可能感兴趣的:(#,概率DP)