P10264 [GESP202403 八级] 接竹竿

GESP8 冲刺课堂页:先建模,再压缩状态,最后读代码。

一、先回答问题

结论

从位置 u 开始,若下一张同点牌在区间内,就整段消掉并跳到 nxt[u]+1。

容易误入的路

每个询问都完整模拟队列,q*n 会超时。

二、核心观察

建模与压缩

nxt[i] 是下一张同点牌;jump[i][k] 表示连续做 2^k 次消除跳跃后的位置。

为什么不丢答案:当当前牌在队底时,它只会被下一张同点牌消掉,中间牌一起清空。

u nxt[u] jump[u][k]

三、互动演示

步骤1
关键状态 A-
关键状态 B-
答案/目标-
复杂度看表
课堂动作手推

四、自己选答案

问题 1

剩余牌为什么最多和点数种类有关?

问题 2

jump 合法条件是什么?

五、手推结果

情况动作答案
nxt[u]<=r跳到 nxt[u]+1不变
nxt[u]>ru 留下,u+++1
多次消除倍增跳加速

课堂要求:每题先说清对象、关系、保留的信息、压缩掉的信息,再写代码。

六、C++14 参考代码

#include <bits/stdc++.h>
using namespace std;

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    
    int q;
    cin >> q;

    int max_jump = n + 2;
    vector<int> nxt(n + 1, max_jump);
    vector<int> last_occ(15, max_jump); // 点数最多 13
    
    for (int i = n; i >= 1; i--) {
        nxt[i] = last_occ[a[i]];
        last_occ[a[i]] = i;
    }

    // jump1[i][k] 表示从 i 开始进行 2^k 次 "消除跳跃" 到达的位置
    vector<vector<int>> jump1(max_jump + 1, vector<int>(15, max_jump));
    for (int i = 1; i <= n; i++) {
        if (nxt[i] <= n) {
            jump1[i][0] = nxt[i] + 1;
        } else {
            jump1[i][0] = max_jump;
        }
    }
    
    for (int k = 1; k < 15; k++) {
        for (int i = 1; i <= max_jump; i++) {
            jump1[i][k] = jump1[jump1[i][k - 1]][k - 1];
        }
    }

    while (q--) {
        int l, r;
        cin >> l >> r;
        int u = l;
        int ans = 0;
        
        while (u <= r) {
            // 利用倍增快速做 "消除跳跃"
            for (int k = 14; k >= 0; k--) {
                // 如果跳跃后的位置在 r+1 以内,说明所有的消除都合法
                if (jump1[u][k] <= r + 1) {
                    u = jump1[u][k];
                }
            }
            
            // 跳不动了,说明当前牌 A_u 的下一次出现超出了 r
            // 这张牌永远不会被消除,答案 +1
            if (u <= r) {
                ans++;
                u++;
            }
        }
        cout << ans << "\n";
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    if (cin >> t) {
        while (t--) {
            solve();
        }
    }
    return 0;
}