1 条题解

  • 0
    @ 2026-10-26 23:48:27

    思路与算法

    按轮次DP,每个结尾值只保留至多两个不同末轮人物编号,足以判断下一人是否可用。扫描每人词库,用长度k-1的滑动窗口统计合格开头位置,产生本轮终点与人物编号。

    正确性说明

    对下一人物p,只需知道上轮这个值是否存在一个人物不等于p:若已有两不同人物必可,只有一个则比较即可,所以保留两个编号不损失信息。当前末位置j可用的开头恰在[j-k+1,j-1]且其值满足上轮人物条件,滑动窗口计数精确覆盖所有长度2..k连续子序列。按轮更新数组、回答该轮询问归纳得正确结果。

    复杂度

    每组O(R*(总词库长度+n+V)+q)时间、O(总词库长度+n+q+V)空间,R<=100、V=200001;含每轮四人物数组清空和询问分桶初始化。

    易错点

    本轮必须只读取上一轮固定数组,不能把当前新状态继续用于同一轮;同一人可以隔轮再次使用,但不能相邻两轮使用。重复字符的不同出现位置均须纳入窗口。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int T;
        cin >> T;
        while (T--) {
            int n, k, q;
            cin >> n >> k >> q;
            vector<vector<int>> s(n);
            for (auto &a : s) {
                int l;
                cin >> l;
                a.resize(l);
                for (int &v : a)
                    cin >> v;
            }
            vector<vector<pair<int, int>>> queries(101);
            vector<int> ans(q);
            int maxr = 0;
            for (int i = 0; i < q; i++) {
                int r, c;
                cin >> r >> c;
                queries[r].push_back({c, i});
                maxr = max(maxr, r);
            }
            const int V = 200001;
            vector<int> a(V, -1), b(V, -1), c(V, -1), d(V, -1);
            a[1] = 0;
            for (int r = 1; r <= maxr; r++) {
                fill(c.begin(), c.end(), -1);
                fill(d.begin(), d.end(), -1);
                for (int p = 0; p < n; p++) {
                    int who = p + 1, count = 0;
                    auto ok = [&](int v) {
                        return a[v] >= 0 && (a[v] != who || b[v] >= 0);
                    };
                    for (int i = 0; i < (int)s[p].size(); i++) {
                        if (i > 0)
                            count += ok(s[p][i - 1]);
                        if (i >= k)
                            count -= ok(s[p][i - k]);
                        if (count) {
                            int v = s[p][i];
                            if (c[v] < 0)
                                c[v] = who;
                            else if (c[v] != who)
                                d[v] = who;
                        }
                    }
                }
                for (auto x : queries[r])
                    ans[x.second] = c[x.first] >= 0;
                a.swap(c);
                b.swap(d);
            }
            for (int v : ans)
                cout << v << "\n";
        }
    }
    
    • 1

    信息

    ID
    1939
    时间
    2000ms
    内存
    128MiB
    难度
    普及+
    标签
    递交数
    0
    已通过
    0
    上传者