1 条题解

  • 0
    @ 2026-5-19 20:51:04

    好的,我们先明确题意,然后结合题目例子和常见解法思路给出详细题解。


    题目理解

    FJ 在时刻 00 位于 侧面 00
    一共有 mm 分钟(时间从 11mm,但注意“第 ii 分钟开始时”的状态会受前一分钟决策影响)。
    每分钟开始时,FJ 可以:

    • 留在当前侧面(不得分)
    • 或者 换到对面(并立即获得 11 分)

    此外,有 nn 个硬性要求: 在第 aia_i 分钟开始时,FJ 必须 在侧面 bib_i

    问:在满足所有音频要求的前提下,FJ 最多能获得多少分(即最多“换边”多少次)?


    关键约束

    • aia_i 严格递增,1aim1 \le a_i \le m
    • 初始时(t=0t=0)在侧面 00,且要求只在 t1t \ge 1 时给出。
    • 如果 tt 时刻没有要求,FJ 可以自由选择留在原位或换边(换边即得分+1)。
    • 如果有要求,tt 时刻位置必须等于 bib_i

    模型转化

    设:

    • pt{0,1}p_t \in \{0,1\} 表示第 tt 分钟开始时(即从 t1t-1 分钟结束到 tt 分钟开始之间决策后)的位置。
    • 初始 p0=0p_0 = 0
    • tt 分钟开始时的决策:可以选择 pt=pt1p_{t} = p_{t-1}(不换边,不得分) 或 pt=1pt1p_{t} = 1 - p_{t-1}(换边,得分+1)。

    要求:pai=bip_{a_i} = b_i

    目标:最大化 换边次数

    等价地,我们要求 最少的“停留”次数 来满足位置约束,因为 mm 分钟内最多可能换 mm 次(每分钟都换),但约束会强制某些时刻不能换或必须换。


    区间思维

    aia_i 看作强制点。

    考虑相邻两个强制点 (ai,bi)(a_i, b_i)(ai+1,bi+1)(a_{i+1}, b_{i+1}),中间 [ai,ai+1][a_i, a_{i+1}] 这段(注意是时间点,不是时刻间隔)。

    我们关心:从 pai=bip_{a_i} = b_i 出发,经过 ai+1aia_{i+1} - a_i 次分钟(每次可换或不换),到达 pai+1=bi+1p_{a_{i+1}} = b_{i+1},最多能换几次?


    换边次数限制

    d=ai+1aid = a_{i+1} - a_i

    结论

    • 如果 bi=bi+1b_i = b_{i+1},即两端相同,那么:

      • 最少换边次数(最少得分为)d%2d \% 2(因为每两次换边回到原位,要满足同侧,必须换偶数次)。
      • 最多换边次数为 dd(如果允许,但必须满足奇偶性约束)。
      • 实际可达的换边次数与 dd 同奇偶,且介于 00dd 之间。
    • 如果 bibi+1b_i \ne b_{i+1},即两端不同:

      • 最少换边次数为 11(换奇数次,最小是 11),
      • 最多换边次数还是 dd,且必须奇数次。

    更精确:
    可达的换边次数集合是:

    $$\{ k \mid k \equiv (b_i \neq b_{i+1}) \pmod{2},\ 0 \le k \le d \} $$

    k=0k=0 只在相同且 dd 偶时才可能;k=1k=1 只在不同且 d1d\ge 1 时才可能。

    不过我们要 最大化总分,所以我们要尽量选大的 kk,但需要保证全局可行。


    抽象成区间问题

    xix_i 表示第 ii 个强制点后的“累积换边次数”奇偶性相关变量。

    实际上,我们可以用 距离 = 时间差 mod 2 来推导约束。

    fif_i 表示从起点到第 ii 个强制点(包含)的总换边次数。

    那么:

    pai=(p0+fi)mod2=(0+fi)mod2p_{a_i} = (p_0 + f_i) \bmod 2 = (0 + f_i) \bmod 2

    因为每次换边会翻转位置,fif_i 就是到此时为止的换边次数。

    要求 pai=bip_{a_i} = b_i,所以:

    fibi(mod2)f_i \equiv b_i \pmod{2}

    同时,从 aia_iai+1a_{i+1}

    fi+1fi=换边次数在区间内f_{i+1} - f_i = \text{换边次数在区间内}

    ki=fi+1fik_i = f_{i+1} - f_i,则:

    • 0kidi0 \le k_i \le d_i,其中 di=ai+1aid_i = a_{i+1} - a_i
    • 奇偶性:kibi+1bi(mod2)k_i \equiv b_{i+1} - b_i \pmod{2}(模 2)。

    并且 f1f_1 对应第一个强制点:f1b1f_1 \equiv b_1


    贪心/DP 构造

    已知 f0=0f_0 = 0,但强制点从 a1a_1 开始。
    t=0t=0a1a_1,有 a1a_1 分钟,我们可以任意安排换边次数 f1f_1(与 b1b_1 同奇偶),且 0f1a10 \le f_1 \le a_1

    然后对于 i=1i=1n1n-1ki=fi+1fik_i = f_{i+1} - f_i,有:

    • kibi+1bi(mod2)k_i \equiv b_{i+1} - b_i \pmod{2}
    • 0kidi0 \le k_i \le d_i

    fif_i 可推 fi+1=fi+kif_{i+1} = f_i + k_i,必须满足 0fi+1ai+10 \le f_{i+1} \le a_{i+1}(因为最多每分钟换一次,所以总换边次数不能超过时间)。

    最后,最后一个强制点后,从 ana_nmm,还有 manm - a_n 分钟,可以继续换边,最大可加分 min(man, 剩余时间)\min(m - a_n,\ \text{剩余时间}) 且奇偶性要匹配最后位置,但注意这最后一段时间没有强制要求,所以可以最大化到 min(man, 时间差)\min(m - a_n,\ \text{时间差}) 且不必考虑奇偶(因为可以最后一步不换)。

    但准确说:最后一段若 ana_nmmT=manT = m - a_n 分钟,我们可以选择在每分钟是否换边,没有奇偶约束(因为结束时没有要求),所以最多可以换 TT 次,即最后一段的最大得分就是 TT


    简化做法

    其实这个问题可以简化为:

    1. 要求 fibif_i \equiv b_i,且 0fiai0 \le f_i \le a_i(因为不能超过时间)。
    2. fi+1fif_{i+1} - f_ibi+1bib_{i+1} - b_i 同奇偶,并且 di\le d_i
    3. 要最大化 fn+(man)f_n + (m - a_n)(最后一段全换)。

    所以关键是最大化 fnf_n,同时满足递推。


    递推求最大 fnf_n

    FiF_i 表示第 ii 个强制点时刻 aia_i 时能达到的最大 fif_i

    初始 $F_1 = \max \{ x \mid x \equiv b_1, 0 \le x \le a_1 \}$
    F1=a1F_1 = a_1 如果 a1b1a_1 \equiv b_1,否则 a11a_1 - 1

    递推:
    Fi+1=min(ai+1, Fi+di)F_{i+1} = \min(a_{i+1},\ F_i + d_i) 且奇偶性必须 Fi+1bi+1F_{i+1} \equiv b_{i+1}

    所以 Fi+1=min(ai+1, Fi+di)F_{i+1} = \min(a_{i+1},\ F_i + d_i) 再调整到满足奇偶性(减 0 或 1)。


    检查可行性

    同时要检查下界:
    最小可达 fi+1f_{i+1}Li+1=max(0, Fidi)L_{i+1} = \max(0,\ F_i - d_i) 吗?等等,不对,因为我们考虑的是 ki0k_i \ge 0,所以 fi+1fidif_{i+1} \ge f_i - d_i 不对,因为 ki=fi+1fik_i = f_{i+1} - f_i 可正可负?
    不能负,因为 ki0k_i \ge 0,即 fi+1fif_{i+1} \ge f_i

    所以 fif_i 必须非递减。
    因此 fi+1fif_{i+1} \ge f_i

    这很重要:换边次数 不会减少,因为每个 kik_i 是区间内增加的次数。

    所以 fif_i 序列单调不减。


    正确递推

    我们有:

    • fi+1fif_{i+1} \ge f_i
    • fi+1bi+1f_{i+1} \equiv b_{i+1}
    • fi+1ai+1f_{i+1} \le a_{i+1}
    • fi+1fi+dif_{i+1} \le f_i + d_i

    并且 fi+1fibi+1bif_{i+1} - f_i \equiv b_{i+1} - b_i

    因此,从 fif_i 出发,要选一个 fi\ge f_i 且同余 bi+1b_{i+1} 的最大值不超过 min(ai+1, fi+di)\min(a_{i+1},\ f_i + d_i)

    M=min(ai+1, fi+di)M = \min(a_{i+1},\ f_i + d_i)

    MM 可能不满足同余,需要减少到满足同余的最接近值。

    所以:

    fi+1=M((Mbi+1)mod2)f_{i+1} = M - ((M - b_{i+1}) \bmod 2)

    同时要检查 fi+1fif_{i+1} \ge f_i,如果 fi+1<fif_{i+1} < f_i,说明不可能,输出 1-1(但题目保证一定有解?不一定,题目没说无解情况,可能输入保证有解,但我们仍可以判断)。


    初始和最终答案

    f1f_1 同样由 min(a1, a1)\min(a_1,\ a_1) 且同余 b1b_1 得: f1=a1f_1 = a_1a1b1a_1 \equiv b_1,否则 a11a_1 - 1,但要检查 f10f_1 \ge 0

    最终答案 = fn+(man)f_n + (m - a_n)


    算法步骤

    1. n,mn, m 和要求数组 (ai,bi)(a_i, b_i)
    2. 对第一个要求:
      • f=a1f = a_1,若 f%2b1f \% 2 \ne b_1f=a11f = a_1 - 1
      • 如果 f<0f < 0,则无解(实际不会)。
    3. ii 从 1 到 n1n-1
      • d=ai+1aid = a_{i+1} - a_i
      • M=min(ai+1, f+d)M = \min(a_{i+1},\ f + d)
      • fnext=M((Mbi+1)&1)f_{next} = M - ((M - b_{i+1}) \& 1)
      • 如果 fnext<ff_{next} < ffnext>ai+1f_{next} > a_{i+1}fnext<0f_{next} < 0,则无解(实际输入保证有解)
      • f=fnextf = f_{next}
    4. 答案 = f+(man)f + (m - a_n)
    5. 输出答案

    代码实现

    #include <bits/stdc++.h>
    using namespace std;
    using ll = long long;
    
    void solve() {
        int n;
        ll m;
        cin >> n >> m;
        vector<ll> a(n);
        vector<int> b(n);
        for (int i = 0; i < n; ++i) {
            cin >> a[i] >> b[i];
        }
        
        ll f;
        // 处理第一个要求
        if (a[0] % 2 == b[0]) {
            f = a[0];
        } else {
            f = a[0] - 1;
        }
        if (f < 0) f = -1; // 无解标记
        
        for (int i = 0; i < n - 1; ++i) {
            if (f < 0) break;
            ll d = a[i+1] - a[i];
            ll M = min(a[i+1], f + d);
            ll nxt = M - ((M - b[i+1]) & 1);
            if (nxt < f || nxt < 0) {
                f = -1;
                break;
            }
            f = nxt;
        }
        
        if (f < 0) {
            // 按照题目保证,这里不会执行
            cout << -1 << "\n";
        } else {
            cout << f + (m - a[n-1]) << "\n";
        }
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int t;
        cin >> t;
        while (t--) solve();
        return 0;
    }
    

    复杂度

    每个测试用例 O(n)O(n),总 nn2×105\le 2\times 10^5,轻松通过。

    • 1

    信息

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