1 条题解

  • 0
    @ 2026-10-27 17:38:04

    思路与算法

    把hh:mm:ss转成t=3600hh+60mm+ss,全部合法秒为0..35999。为PVCDB五种乐器分别开差分数组。观测闭区间[L,R]使diff[L]加1、diff[R+1]减1,全部观测读完后分别做前缀和。查询t时按PVCDB顺序检查五个覆盖次数,正数就输出该字母;全为0输出None。

    正确性说明

    一条闭区间观测在t<L时差分前缀贡献0,在L≤t≤R时贡献1,在t>R时贡献再次变0。因此叠加所有观测后,各乐器的前缀和恰为覆盖当前秒的朋友资料条数;大于0当且仅当根据资料该乐器在这一秒演奏。按每种乐器仅检查一次避免重叠资料重复输出,固定PVCDB遍历满足规定顺序,全0时的None也恰合定义。

    复杂度

    设H=36000。五个差分数组的零初始化和前缀和O(5H),N条观测O(N),M次查询O(5M),总O(N+5H+5M),空间O(5H)。时间串固定8字符,转换为O(1),输入和输出代价已计入。

    易错点

    区间包含结束秒,R+1才减1,单秒L=R仍有效。最大时刻09:59:59对应35999,数组要额外留36000哨兵。重叠的相同乐器是覆盖次数累加,不是异或;只要次数正就显示一次。输出顺序PVCDB不是字母表序,None大小写固定。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    int seconds(const string &s) {
        return stoi(s.substr(0, 2)) * 3600 + stoi(s.substr(3, 2)) * 60 + stoi(s.substr(6, 2));
    }
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int n;
        if (!(cin >> n))
            return 0;
        const string order = "PVCDB";
        const int H = 36000;
        vector<vector<int>> diff(5, vector<int>(H + 1));
        for (int i = 0; i < n; i++) {
            string a, b;
            char c;
            cin >> a >> b >> c;
            int type = order.find(c), l = seconds(a), r = seconds(b);
            diff[type][l]++;
            diff[type][r + 1]--;
        }
        for (int k = 0; k < 5; k++)
            for (int t = 1; t < H; t++)
                diff[k][t] += diff[k][t - 1];
        int m;
        cin >> m;
        while (m--) {
            string s, result;
            cin >> s;
            int t = seconds(s);
            for (int k = 0; k < 5; k++)
                if (diff[k][t] > 0)
                    result += order[k];
            cout << (result.empty() ? "None" : result) << '\n';
        }
    }
    
    • 1

    信息

    ID
    2127
    时间
    1000ms
    内存
    64MiB
    难度
    普及−
    标签
    递交数
    0
    已通过
    0
    上传者