1 条题解

  • 0
    @ 2025-11-11 11:03:54

    题目理解

    我们有一个牌堆,从上到下编号为 11NN。每次可以:

    • 拿走第 11 张牌(栈顶)
    • 或者拿走第 33 张牌

    限制条件:每次拿的牌必须与上一次拿的牌在花色点数上相同。

    目标:最大化拿走的牌的价值总和。

    关键观察

    1. 操作的影响

    当我们拿走一张牌时,牌堆的结构会发生变化:

    • 如果拿走第 11 张牌:牌 22 成为新的牌 11,牌 33 成为新的牌 22,依此类推
    • 如果拿走第 33 张牌:牌 1,21,2 位置不变,牌 44 成为新的牌 33,依此类推

    2. 状态表示

    由于每次只能拿第 11 张或第 33 张牌,牌堆的状态可以用当前的前几张牌来表示。

    经过分析,任何时候牌堆的状态可以描述为:

    • 当前的第 11 张牌(原来的某张牌)
    • 当前的第 22 张牌(原来的某张牌)
    • 以及从某个位置开始往后的连续牌序列

    更具体地说,状态可以定义为 (i,j)(i, j),表示:

    • 11 是原来的第 ii 张牌
    • 22 是原来的第 jj 张牌
    • 33 及之后的牌是原来的第 max(i,j)+1\max(i,j)+1 张牌开始的连续序列

    3. 动态规划状态设计

    dp[i][j]dp[i][j] 表示:

    • 当前牌 11 是原来的第 ii 张牌
    • 当前牌 22 是原来的第 jj 张牌
    • 且上一次拿的牌是某张特定牌(这个信息需要额外维护)

    但是这样还不够,我们还需要知道上一次拿的牌的信息来检查合法性。

    更好的状态设计: dp[i][j][k]dp[i][j][k] 表示:

    • 11 是原来的第 ii 张牌
    • 22 是原来的第 jj 张牌
    • 上一次拿的牌是原来的第 kk 张牌(k=0k=0 表示还没有拿过牌)

    在这种状态下能获得的最大价值。

    算法思路

    1. 状态转移

    从状态 (i,j,k)(i, j, k) 出发,有两种选择:

    选择1:拿走牌 11(原来的第 ii 张牌)

    • 条件:k=0k = 0Ci=CkC_i = C_kAi=AkA_i = A_k
    • 新状态:(j,i+1,i)(j, i+1, i)
    • 价值增加:ViV_i

    选择2:拿走牌 33(原来的第 max(i,j)+1\max(i,j)+1 张牌)

    • 条件:k=0k = 0Cmax(i,j)+1=CkC_{\max(i,j)+1} = C_kAmax(i,j)+1=AkA_{\max(i,j)+1} = A_k
    • 新状态:(i,j+1,max(i,j)+1)(i, j+1, \max(i,j)+1)
    • 价值增加:Vmax(i,j)+1V_{\max(i,j)+1}

    2. 初始化

    初始状态:(1,2,0)(1, 2, 0),表示牌 11 是原来的第 11 张,牌 22 是原来的第 22 张,还没有拿过牌。

    3. 边界条件

    i>Ni > Nj>Nj > N 时,表示没有牌可拿了。

    总结

    这道题的关键在于:

    1. 理解操作规则:只能拿第 11 张或第 33 张牌,且必须与上一张牌花色或点数相同
    2. 状态设计:用 (i,j)(i, j) 表示当前牌堆的前两张牌
    3. 关键优化:发现 ji2j - i \leq 2 的性质,大幅减少状态数
    4. 动态规划:正确处理状态转移和边界条件

    通过巧妙的状态设计和优化,我们可以在 O(N2)O(N^2) 时间内解决这个看似复杂的问题。

    • 1

    #3002. 「JOISC 2015 Day 3」Card Game Is Great Fun

    信息

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