ABC382 C-F题解

C - Kaiten Sushi

把寿司都放到一个堆里,从前往后扫 \(A\) 数组,如果当前食客 \(A_i\) 小于等于堆顶,就取出堆顶,记录这份寿司被第 \(i\) 个人吃掉。复杂度 \(O(n\log m)\)

D - Keep Distance

搜索回溯,但每一步从 \(10\) 枚举到 \(m\) 会超时,剪一下枝 for (int i = 10; res.back() + i <= m - 10 * (n - siz - 1); i++)

E - Expansion Packs

\(f_i\) 表示再拿 \(i\) 个稀有卡期望 \(f_i\) 步,发现 \(f_i=1+f_ig_0+f_{i-1}g_1+f{i-2}g_2+\cdots\)。把 \(f_ig_0\) 移到等式左边,有 \((1-g_0)f_i=1+\sum\limits_{j=1}^i f_{i-j}g_j\),其中 \(g_j\) 表示从一个袋子里拿到 \(j\) 个稀有卡的概率。得到 dp 方程 \(f_i=\dfrac{1+\sum\limits_{j=1}^i f_{i-j}g_j}{1-g_0}\)

\(g\) 数组可以通过 \(O(n^2)\) 的 dp 求出。设 \(dp_{i,j}\) 表示一个袋子里前 \(i\) 张卡中有 \(j\) 个稀有卡的概率,于是有 \(dp_{i,j}=dp_{i-1,j-1}p_i+dp_{i-1,j}(1-p_i)\),注意 \(j=0\) 时的边界情况。\(dp_{n,j}\) 即为 \(g_j\)

void solve() {
    using f128 = long double;
    int n, x;
    cin >> n >> x;
    vector<f128> p(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> p[i];
        p[i] /= 100;
    }
    vector dp(n + 1, vector<f128>(n + 1));
    dp[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= i; j++) {
            dp[i][j] = dp[i - 1][j] * (1 - p[i]);
            if (j) dp[i][j] += dp[i - 1][j - 1] * p[i];
        }
    }
    vector<f128> f(x + 1, 1);
    vector<f128>& g = dp[n];
    f[0] = 0;
    for (int i = 1; i <= x; i++) {
        for (int j = 1; j <= min(n, i); j++)
            f[i] += f[i - j] * g[j];
        f[i] /= (1 - g[0]);
    }
    cout << fixed << setprecision(16) << f[x] << '\n';
}

F - Falling Stars

把横线从下到上排序,开一棵线段树记录每个位置摞了多少层。要加入一条横线的时候,先查询对应区间 \([C_i,C_i+L_i-1]\) 的最小值(最高层数)\(r\),则该横线的层数就是 \(r-1\),区间赋值 \(r-1\) 即可。AC代码

posted @ 2024-12-07 19:35  XYukari  阅读(35)  评论(0)    收藏  举报