1 条题解

  • 0
    @ 2026-6-19 10:31:10

    📝 题目大意

    LL 把椅子排成一列,NN 组人依次到来,每组 1122 人,总人数恰好等于 LL。每组随机选择一个能容纳本组人数的连续空位坐下。判断是否无论随机选择如何,都能保证所有组全部坐下而无人离开。

    💡 解题思路

    1. 题目分析:每组只有 11 人或 22 人(ai{1,2}a_i \in \{1,2\}),且总人数之和等于 LL。唯一会导致有人无法坐下的情况是:某组 22 人到来时,剩余空位全部分散为孤立单椅(即不存在任何两个相邻空位)。因此问题转化为:是否存在一种最坏情况的随机选择,使得在某个 22 人组到来时,所有剩余空位都是孤立的。

    2. 算法推导: 考虑一个对抗者(adversary),他可以在每组到来时选择最不利的放置位置,试图最大化"孤立单椅"的数量。我们维护两个变量:

      • LL:当前剩余椅子中,属于某个"连续大块"的椅子数(即非孤立的椅子总数)。
      • oneone:当前已经被孤立出来的单椅数量。

      初始时 LL 为总椅子数,one=0one = 0,即所有椅子在一个大连续块中。

      对抗者的最优策略始终是:将当前组放在连续块的边界,尽可能制造孤立单椅。具体地:

      • 处理 11 人组

        • L=0L = 0:连续块已空,只能消耗一个孤立单椅(oneone1one \leftarrow one - 1)。
        • L=1L = 1:连续块恰剩 11 椅,直接使用,块消失(L0L \leftarrow 0)。
        • L2L \geq 2:对抗者将 11 人放在连续块边界,占据 11 椅,同时将相邻的 11 椅割裂为孤立单椅。因此连续块缩小 22LL2L \leftarrow L - 2),孤立单椅增加 11oneone+1one \leftarrow one + 1)。
      • 处理 22 人组

        • L1L \leq 1:连续块中无法容纳 22 人,且孤立单椅也无法容纳 22 人 → 输出 No
        • L=2L = 2:连续块恰为 22 椅,恰好容纳(L0L \leftarrow 0)。
        • L3L \geq 3:对抗者将 22 人放在连续块边界,占据 22 椅,割裂相邻的 11 椅为孤立单椅。连续块缩小 33LL3L \leftarrow L - 3),孤立单椅增加 11oneone+1one \leftarrow one + 1)。

      正确性说明:为什么对抗者每次只制造 11 个孤立单椅?因为 ai{1,2}a_i \in \{1,2\},一组最多占据 22 个连续位置,在边界放置时最多只能将 11 个相邻椅子与主块割裂。对抗者无法通过一次放置制造更多孤立单椅。同时,制造孤立单椅总是有利于对抗者(孤立单椅只能容纳 11 人组,对后续 22 人组构成威胁),因此该策略确实是最优的。

      如果遍历完所有组后仍未触发 No,则说明即使最坏情况也无法迫使任何人离开,输出 Yes

    3. 边界与细节

      • L=0L = 0one>0one > 0 时,只有 11 人组能消耗孤立单椅,22 人组会直接失败。
      • 变量 one 可能变为负数吗?不会,因为 L+oneL + one 始终等于剩余椅子总数,且 L0L \geq 0,只有当 L=0L = 0one>0one > 0 时才会 one--,此时 oneone 至少为 11
      • 数据范围 N2×105N \leq 2 \times 10^5O(N)O(N) 的模拟完全可行。

    ⏱️ 复杂度分析

    • 时间复杂度:仅需对 NN 个组进行一次线性扫描,每次 O(1)O(1) 处理,总复杂度 O(N)O(N)
    • 空间复杂度:仅使用常数个变量(Lonea),无需额外数组,空间复杂度 O(1)O(1)

    💻 标准代码 (C++)

    #include <bits/stdc++.h>
    using namespace std;
    int main(){
        int N, L; 
        cin >> N >> L;
        int one = 0;                // 已制造出的孤立单椅数量
        while(N--){
            int a; 
            cin >> a;
            if(a == 1){
                if(L == 0)
                    one--;          // 连续块已空,消耗一个孤立单椅
                else if(L == 1)
                    L--;            // 连续块仅剩1椅,直接使用
                else
                    L -= 2, one++;  // 从连续块取2椅,用1椅,留1椅孤立
            } else {                // a == 2
                if(L <= 1){
                    cout << "No\n"; // 无法容纳2人组,对抗者获胜
                    return 0;
                }
                if(L == 2)
                    L -= 2;         // 连续块恰为2椅,恰好容纳
                else
                    L -= 3, one++;  // 从连续块取3椅,用2椅,留1椅孤立
            }
        }
        cout << "Yes\n";            // 所有组均能坐下
    }
    

    信息

    ID
    873
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者