CF1278F Cards

Posted yijan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1278F Cards相关的知识,希望对你有一定的参考价值。

CF1278F Cards

首先我们知道,一次拿牌的概率是 $ P(i) = frac 1 m $ ,同时权值是1,所以期望就是 $ frac{1} m $,拿 $ n $ 次牌贡献是独立的,就是 $ frac n m $。

但是我们要算的是 $ k $ 次方的期望,众所周知期望的二次方不等于二次方的期望。我们考虑 $ E $ 的意义,$ E $ 在这一次拿到 Joker 的 $ frac 1 m $ 的概率下是 1 ,其他情况是0。则 $ E^2 $ 就是随机两次,这两次都是 1 的情况下是 1 ,其他情况是0。

我们把这 $ n $ 次是否抓到 Joker 的 0/1 写成一个序列,所以知道最后统计的答案,就是所有的长度为 $ k $ 的有序子序列(可以是 $ A_3,A_2,A_2 $ 这种的 ),它做出贡献的前提就是这个子序列的所有随机变量都去到 1 了。

接着考虑,如果两个序列的位置种类数一致,那么它们出现的概率是相同的。如果知道这些位置都是 Joker ,那么这些位置组成的所有序列都会出现。

所以考虑一个 dp ,$ dp[i][j] $ 表示当前在选择第 $ i $ 个位置,到达这个位置时已经有 $ j $ 个不同的位置出现了。那么 $ sum dp[k][i] imes frac{1}{m^{i}} $ 就是答案,因为有 $ frac{1}{m^i} $ 的概率这 $ i $ 个钦定的元素位置都是 Joker,这样带来的权值就是方案数。然后考虑这个 dp 的递推,这是很轻松的:
[ dp[i][j] = dp[i-1][j] imes j + dp[i-1][j-1] imes (n-j+1) ]
就是考虑第 $ i $ 个位置是选择前 $ j $ 个之一还是新选择一种。

代码很简单:

#include "algorithm"
#include "iostream"
#include "cstring"
#include "cstdio"
using namespace std;
#define MAXN 5006
#define P 998244353
int n , m , k;
int dp[MAXN][MAXN];
int Pow( int a , int b ) {
    int cur = a % P , ans = 1;
    while( b ) {
        if( b & 1 ) ans = 1ll * ans * cur % P;
        cur = 1ll * cur * cur % P , b >>= 1;
    }
    return ans;
}
int main( ) {
    cin >> n >> m >> k;
    dp[0][0] = 1;
    for( int i = 1 ; i <= k ; ++ i ) {
        for (int j = 1; j <= i; ++j)
            dp[i][j] = ( 1ll * dp[i-1][j] * j % P + 1ll * dp[i-1][j-1] * ( n - j + 1 ) % P ) % P;
    }
    int res = 0 , cur = 1 , p = Pow( m , P - 2 );
    for( int i = 0 ; i <= k ; ++ i )
        ( res += 1ll * dp[k][i] * cur % P ) %= P , cur = 1ll * cur * p % P;
    cout << res << endl;
}

以上是关于CF1278F Cards的主要内容,如果未能解决你的问题,请参考以下文章

CF1278F Cards

题解 CF546C Soldier and Cards

CF1172A Nauuo and Cards 贪心

[CF1539E]Game with Cards

[CF743E] Vladik and cards

CF949E Binary Cards 题解