1 条题解
-
0
思路与算法
把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