1 条题解

  • 0
    @ 2026-5-7 20:22:30

    D1. 乌龟与 MEX 问题(简单版本) — 详细题解


    一、问题重述

    给定 nn 个序列,第 ii 个序列为 ai,1,ai,2,,ai,lia_{i,1}, a_{i,2}, \dots, a_{i,l_i}
    初始有一个非负整数 x=kx = k。每次操作可以选择一个序列 ii,并将 xx 更新为:

    $$x \leftarrow \operatorname{mex}(x, a_{i,1}, a_{i,2}, \dots, a_{i,l_i}) $$

    其中 mex\operatorname{mex} 定义为最小的未出现在集合中的非负整数。
    操作可以进行任意多次(包括零次),同一个序列可以被重复选择。

    定义 f(k)f(k) 为从初始值 kk 出发,通过最优操作能达到的 最大 xx 值。

    给定 mm,需要计算:

    i=0mf(i)=f(0)+f(1)++f(m)\sum_{i=0}^{m} f(i) = f(0) + f(1) + \dots + f(m)

    二、单个序列的性质

    2.1 定义关键值

    对于第 ii 个序列 Si={ai,1,,ai,li}S_i = \{a_{i,1}, \dots, a_{i,l_i}\},定义两个重要值:

    • 第一 MEXpi=mex(Si)p_i = \operatorname{mex}(S_i),即 SiS_i 中缺失的最小非负整数。
    • 第二 MEXqi=mex(Si{pi})q_i = \operatorname{mex}(S_i \cup \{p_i\}),即 SiS_i 加上 pip_i 后缺失的最小非负整数。

    注意:qiq_i 也可以描述为 大于 pip_i 的第一个不在 SiS_i 中的整数

    2.2 单次操作的效果

    对序列 ii 执行一次操作,设当前值为 xx

    情况 1x=pix = p_i

    此时 xx 恰好是 SiS_i 缺失的最小值。加上 xx 后,pip_i 被填补,因此新的 mex 变为下一个缺失值:

    mex(pi,Si)=qi\operatorname{mex}(p_i, S_i) = q_i

    情况 2xpix \neq p_i

    此时 pip_i 仍然不在 Si{x}S_i \cup \{x\} 中(因为 xpix \neq p_i),且所有小于 pip_i 的数都在 SiS_i 中。因此最小缺失值仍是 pip_i

    mex(x,Si)=pi\operatorname{mex}(x, S_i) = p_i

    总结(核心性质):

    $$\operatorname{mex}(x, S_i) = \begin{cases} q_i, & \text{if } x = p_i \\[4pt] p_i, & \text{if } x \neq p_i \end{cases} $$

    三、可达值分析

    3.1 从单个序列能到达的值

    从任意 xx 出发,对序列 ii 重复操作:

    • xpix \neq p_i,一次操作后 xx 变为 pip_i
    • x=pix = p_i,一次操作后 xx 变为 qiq_i
    • x=qix = q_i,由于 qipiq_i \neq p_i,一次操作后 xx 变回 pip_i

    因此,pip_iqiq_i 之间可以来回切换。从任意 xx 出发,最多两步就能到达 qiq_i(先到 pip_i,再到 qiq_i)。

    3.2 多个序列的协同

    考虑所有 nn 个序列,设:

    M=maxi=1nqiM = \max_{i=1}^{n} q_i

    定理:从任意 xMx \le M 出发,可以到达 MM

    证明

    1. 取达到 MM 的那个序列 jj,即 qj=Mq_j = M
    2. 若当前 x=pjx = p_j,一步到 MM
    3. 若当前 xpjx \neq p_j,一步到 pjp_j,再一步到 MM
    4. 若当前 xx 不是 pjp_j 且无法直接到 pjp_j?实际上任何 xx 都可以通过合适的序列调整到 pjp_j 吗?需要更细致的论证,但结论成立。

    定理:从任意 x>Mx > M 出发,无法到达大于 xx 的数。

    证明

    • 任何操作的结果要么是某个 pip_iM\le M),要么是某个 qiq_iM\le M)。
    • 因此操作只会得到不超过 MM 的值。
    • 由于 x>Mx > M,最优策略是 不进行任何操作,保留 xx 本身。

    因此:

    $$f(k) = \begin{cases} M, & \text{if } k \le M \\[4pt] k, & \text{if } k > M \end{cases} $$

    其中 M=max{q1,q2,,qn}M = \max\{q_1, q_2, \dots, q_n\}


    四、求和公式

    M=maxi=1nqiM = \max_{i=1}^n q_i。根据 mmMM 的大小关系,分两种情况计算 k=0mf(k)\displaystyle \sum_{k=0}^m f(k)

    情况 1:mMm \le M

    对所有 k=0,1,,mk = 0, 1, \dots, m,有 f(k)=Mf(k) = M
    共有 m+1m+1 项,因此:

    k=0mf(k)=(m+1)M\sum_{k=0}^m f(k) = (m+1) \cdot M

    情况 2:m>Mm > M

    • k=0,1,,Mk = 0, 1, \dots, M 时,f(k)=Mf(k) = M,共 M+1M+1 项,贡献 (M+1)M(M+1) \cdot M
    • k=M+1,M+2,,mk = M+1, M+2, \dots, m 时,f(k)=kf(k) = k,这是一个等差数列:
      • 首项 a1=M+1a_1 = M+1
      • 末项 an=ma_n = m
      • 项数 n=mMn = m - M

    等差数列求和公式:

    $$\sum_{k=M+1}^m k = \frac{(M+1 + m) \cdot (m - M)}{2} $$

    总答案为:

    $$\sum_{k=0}^m f(k) = (M+1) \cdot M + \frac{(M+1 + m)(m - M)}{2} $$

    五、算法步骤

    1. 对每个序列 ii
      • lil_i 个元素存入集合(或排序后去重)。
      • 计算 pip_i:从 00 开始找第一个不在集合中的整数。
      • 计算 qiq_i:从 pi+1p_i+1 开始找第一个不在集合中的整数。
    2. 计算 M=max{q1,q2,,qn}M = \max\{q_1, q_2, \dots, q_n\}
    3. 根据 mmMM 的关系,用上述公式计算答案。

    时间复杂度O(lilogli)O(\sum l_i \log l_i),满足 2×1052 \times 10^5 的限制。


    六、代码实现(标程)

    #include <bits/stdc++.h>
    using namespace std;
    
    void solve() {
        int n;
        long long m;
        cin >> n >> m;
        
        int M = 0;  // 存储所有 q_i 的最大值
        
        for (int i = 0; i < n; i++) {
            int l;
            cin >> l;
            set<int> st;
            for (int j = 0; j < l; j++) {
                int x;
                cin >> x;
                st.insert(x);
            }
            
            // 计算 p_i(第一个缺失)
            int p = 0;
            while (st.count(p)) p++;
            
            // 计算 q_i(大于 p 的第一个缺失)
            int q = p + 1;
            while (st.count(q)) q++;
            
            M = max(M, q);
        }
        
        long long ans = 0;
        
        if (m <= M) {
            ans = (m + 1) * M;
        } else {
            ans = (long long)(M + 1) * M;               // 0..M 部分
            ans += (M + 1 + m) * (m - M) / 2;          // M+1..m 部分
        }
        
        cout << ans << "\n";
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        
        int t;
        cin >> t;
        while (t--) {
            solve();
        }
        
        return 0;
    }
    

    七、样例验证

    样例 1

    序列:

    1. {0,2}\{0,2\}p=1p=1q=3q=3
    2. {2,3,3}\{2,3,3\}p=0p=0q=1q=1
    3. {7,0,1,5}\{7,0,1,5\}p=2p=2q=3q=3

    M=max(3,1,3)=3M = \max(3, 1, 3) = 3m=4>Mm = 4 > M,情况 2:

    $$\text{ans} = (3+1) \times 3 + \frac{(3+1+4)(4-3)}{2} = 4 \times 3 + \frac{8 \times 1}{2} = 12 + 4 = 16 $$

    与样例输出一致 ✅

    样例 2

    序列:

    1. {0,2,0,4,11}\{0,2,0,4,11\}:去重后 {0,2,4,11}\{0,2,4,11\}p=1p=1q=3q=3
    2. {1,1}\{1,1\}{1}\{1\}p=0p=0q=2q=2
    3. {1,3,0,3,3}\{1,3,0,3,3\}{0,1,3}\{0,1,3\}p=2p=2q=4q=4

    M=max(3,2,4)=4M = \max(3, 2, 4) = 4m=4Mm = 4 \le M,情况 1:

    ans=(4+1)×4=20\text{ans} = (4+1) \times 4 = 20

    与样例输出一致 ✅

    样例 4

    序列:

    1. {1,2}\{1,2\}p=0p=0q=3q=3
    2. {1,2}\{1,2\}p=0p=0q=3q=3

    M=3M = 3m=1Mm = 1 \le M,情况 1:

    ans=(1+1)×3=6\text{ans} = (1+1) \times 3 = 6

    与样例输出一致 ✅


    八、注意事项

    1. 使用 long long 存储答案,因为 mm 可达 10910^9,求和可能超过 3232 位整数范围。
    2. ai,ja_{i,j} 可能远大于 nn,但寻找 pip_iqiq_i 时只需检查到 li+2l_i+2 即可,为简单起见直接用 set 存储所有值。
    3. 输入数据量大,建议使用 ios::sync_with_stdio(false)cin.tie(nullptr) 加速。
    • 1

    信息

    ID
    7004
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    2
    已通过
    1
    上传者