CF1156F Card Bag

Link
显然赢当且仅当取牌的序列构成了一个单调上升的序列并且最后两个数相等。
先把(a)排序,然后考虑dp,设(f_{i,j})表示取了(i)张牌,第(i)张牌是(j)且游戏尚未结束的概率。
为了方便我们规定同样大小的牌必须先取小的。
因此我们有:
(egin{cases}f_{i,j}=frac{(sumlimits_{k=1}^{j-1}f_{i-1,k})cnt_j}{n-i+1}&a_j e a_{j-1}\ans+=frac{f_{i-1,j-1}(cnt_j-1)}{n-i+1}end{cases})
其中(cnt)是桶。

#include<cstdio>
#include<algorithm>
const int N=5007,P=998244353;
int read(){int x;scanf("%d",&x);return x;}
void mod(int&x){x-=P,x+=x>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int a[N],cnt[N],f[N][N],sum[N][N],inv[N];
int main()
{
    int n=read(),ans=0;inv[0]=inv[1]=1;
    for(int i=2;i<=n;++i) inv[i]=mul(inv[P%i],P-P/i);
    for(int i=1;i<=n;++i) ++cnt[a[i]=read()];
    std::sort(a+1,a+n+1),std::fill(sum[0],sum[0]+n+1,1),f[0][0]=1;
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=n;j++) a[j]==a[j-1]? (mod(ans+=mul(mul(f[i-1][j-1],inv[n-i+1]),cnt[a[j]]-1)),0):f[i][j]=mul(mul(sum[i-1][j-1],inv[n-i+1]),cnt[a[j]]);
        for(int j=1;j<=n;++j) mod(sum[i][j]=sum[i][j-1]+f[i][j]);
    }
    printf("%d",ans);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12243704.html