问题描述
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N 行。
其中每一行的格式是:
ts id
表示在 ts 时刻编号 id 的帖子收到一个”赞”。
现在小明想统计有哪些帖子曾经是”热帖”。
如果一个帖子曾在任意一个长度为 D 的时间段内收到不少于 K 个赞,小明就认为这个帖子曾是”热帖”。
具体来说,如果存在某个时刻 T 满足该帖在 [T,T+D) 这段时间内(注意是左闭右开区间)收到不少于 K 个赞,该帖就曾是”热帖”。
给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。
输入格式
第一行包含三个整数 N,D,K。
以下 N 行每行一条日志,包含两个整数 ts 和 id。
输出格式
按从小到大的顺序输出热帖 id。
每个 id 占一行。
数据范围
1≤K≤N≤105,
0≤ts,id≤105,
1≤D≤10000
输入样例:
7 10 2 0 1 0 10 10 10 10 1 9 1 100 3 100 3
输出样例:
1 3
思路
具体思路如下:
1.将输入的日志按照时间从小到大进行排序。
2.枚举每一条日志,用一个数组 cnt 来记录当前时间间隔内每个 id 的点赞数。同时将已经不在热度规定时间间隔内的帖子减去相应的点赞,保证 cnt 中记录的点赞数是在时间间隔内的。如果在热度规定的时间间隔内点赞数大于等于 k,则在 st 中标记该 id 为热帖即标记为 true。
3.遍历 st 数组,如果为 true 则输出相应的 id。
我们举个例子,假设 n=7, d=5, k=3,看一看该过程的中间部分:
可以发现当时间窗口长度刚好为 5 时,id 为 1 的帖子满足了热帖的要求,所以在 st 中将其标记为热帖。然后我们继续往后操作即 i 继续增加,发现时间窗口长度超过了 5,故需要将 j 往后移动,同时修改 cnt 中对应的值。
代码
#include<bits/stdc++.h> using namespace std; typedef pair<int, int> PII; const int N = 100010; int n, d, k; PII logs[N]; int cnt[N]; bool st[N] = { 0 }; int main() { cin >> n >> d >> k; for (int i = 0; i < n; i++) scanf("%d%d", &logs[i].first, &logs[i].second); //按照时间从小到大排序 sort(logs, logs + n); //按照时间从小到大枚举日志 for (int i = 0, j = 0; i < n; i++) { int id = logs[i].second; cnt[id]++; //当前id点赞数加一 //减去已经在规定热度时间间隔之外的id点赞 while (logs[i].first - logs[j].first >= d) { cnt[logs[j].second]--; j++; } //如果该时间间隔内点赞数已经大于等于k,则记录该热帖 if (cnt[id] >= k) st[id] = true; } //输出热帖id for (int i = 0; i <= 100000; i++) if (st[i]) printf("%d\n", i); return 0; }