minmax容斥 - 2026/8/26 NOIP模拟赛A题

传送门

传送门

原题

题目背景

叠甲:本场原题数量多,且很板,有些大佬可能全做过,如果 AK 了不要喷题简单,谢谢!

大 B 是小 N 的粉丝。

题目描述

有 \(n\) 张小 N 的图片。接下来每一天,你会重复 \(k\) 次:等概率独立随机选择一张小 N 的图片,加入大 B 的图库。

请问期望几天结束后,第一次满足大 B 的图库中包含所有小 N 的 \(n\) 张图片?由于你不喜欢小数,你只想知道答案对 \(998244353\) 取模的结果,也即:设答案为 \(\dfrac{P}{Q}\),其中 \((P,Q)=1,\ P,Q\in\mathbb{Z}\),你要输出一个 \(x\) 满足 \(0 \le x < 998244353,\ P - Qx \equiv 0 \pmod{998244353}\)。

形式化题意

给定 \(n,k\)。有一个不可重集 \(S\),初始 \(S=\varnothing\)。接下来每次操作,你重复 \(k\) 次将 \([1,n]\) 的独立等概率随机整数加入 \(S\)。问期望几次操作后,第一次满足 \(|S|=n\)。答案对 \(998244353\) 取模。

注:
\(\forall 1 \le i < n,\ i^k \not\equiv n^k \pmod{998244353}\)。

输入格式

输入包含一行两个整数 \(n,k\),表示小 N 的图片数量与你每天重复加图的次数。

输出格式

输出包含一行一个自然数,表示答案。

输入输出样例

样例 #1

样例输入 #1

3 2

样例输出 #1

573990506

说明/提示

对于所有数据,保证:

  • \(1 \le n,k \le 3 \times 10^5\);
  • \(\forall 1 \le i < n,\ i^k \not\equiv n^k \pmod{998244353}\)。

子任务

子任务编号 \(n\) 的范围 \(k\) 的范围 分值
1 \(\le 8\) \(\le 8\) 1
2 \(\le 3\times 10^5\) \(=1\) 18
3 \(\le 40\) \(\le 40\) 31
4 \(\le 3000\) \(\le 3000\) 10
5 \(\le 3\times 10^5\) \(\le 3\times 10^5\) 40

思路

minmax容斥 的标准形式:对于一个不可重集 \(S\)(若 \(S\) 中有重复元素,通过强制为其规定大小关系可转化为不可重集进行操作)有:

\[\max_{a_i\in S}a_i=\sum_{T\sube S}(-1)^{|T|-1}\times\min_{a_i\in T}a_i \]

这个式子对于期望形式也是成立的。
对于本题来说,我们先来转化所求:设 \(t_i\) 代表第 \(i\) 张图片期望在第 \(t_i\) 天出现,那么我们可以把所求写为 \(\max\{t_1,t_2,\dots,t_n\}\)。

运用 minmax容斥:

\[\max_{t_i\in S}t_i=\sum_{T\sube S}(-1)^{|T|-1}\times\min_{t_i\in T}t_i \]

由于图片之间没有差别,我们通过对称性得到,对于一个大小为 \(m\) 的 \(T\in S\),其最小值代表的是 \(T\) 中出现最早的元素,这个事情是十分容易搞出来的。

首先,我们知道,每一次操作(注意不是一天)抽到 \(T\) 中元素的概率是 \(\sum_{t_i\in T}p_i=m\times p\),其中 \(p=\frac1n\),故一天抽 \(k\) 次抽中 \(T\) 中元素的概率 \(P_0=1-(\frac {n-m}n)^k\)。我们接下去计算期望多少天可以抽中 \(T\) 中的元素:

\[P=\sum_{day=1}^\infty ((\frac {n-m}n)^k)^{day-1}\times P_0\times day \]

令 \(p=\frac {n-m}n\),则

\[\begin{aligned} P_m&=P_0\times\sum_{x=1}^\infty (1-P_0)^{x-1}\times x\\&=P_0(1+2(1-P_0)+3(1-P_0)^2+\dots)\\&=P_0\cdot\frac1{(1-(1-P_0))^2}\\&=\frac1{P_0}\\&=\frac1{1-(\frac{n-m}n)^k} \end{aligned} \]

我们将这个结果套到 minmax容斥 的式子里:

\[\begin{aligned} \text{ans}&=\sum_{i=1}^n \binom n i\times P_i\times(-1)^{i+1}\\& =\sum_{i=1}^n\binom ni\times(-1)^{i+1}\times\frac1{1-(\frac{n-i}n)^k} \end{aligned} \]

AC Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int MOD = 998244353;
const int INF = 2e9; // const ll INF = 4e18
const int N = 3e5 + 5;
ll qpow(ll a, ll b) {
    ll ret = 1;
    while (b) {
        if (b & 1) ret = ret * a % MOD;
        a = a * a % MOD;
        b >>= 1;
    }
    return ret;
}
ll n, k;
ll ans;
ll fact[N], rev[N];
ll C(int n, int m) {
    ll ret = fact[n] * rev[n - m] % MOD;
    ret = ret * rev[m] % MOD;
    return ret;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> k;
    fact[0] = 1;
    for (int i = 1; i <= n; ++i) {
        fact[i] = fact[i - 1] * i % MOD;
    }
    rev[n] = qpow(fact[n], MOD - 2);
    for (int i = n; i; --i) {
        rev[i - 1] = rev[i] * i % MOD;
    }
    ll f = 1;
    for (int i = 1; i <= n; ++i) {
        ll tmp = qpow(n, MOD - 2) * (n - i) % MOD;
        tmp = (1 - qpow(tmp, k)) % MOD;
        if (tmp < 0) tmp += MOD;
        tmp = qpow(tmp, MOD - 2);
        (ans += f * C(n, i) * tmp) %= MOD;
        f *= -1;
    }
    if (ans < 0) ans += MOD;
    cout << ans << '\n';
    return 0;
}
posted @ 2026-08-26 14:35  peter_code  阅读(12)  评论(0)    收藏  举报