2018年第九届蓝桥杯C++省赛B组H题
日志统计
小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有N行。其中每一行的格式是:
ts id
表示在ts时刻编号id的帖子收到一个"赞"。
现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖子曾在任意一个长度为D的时间段内收到不少于K个赞,小明就认为这个帖子曾是"热帖"。
具体来说,如果存在某个时刻T满足该帖在[T, T+D)这段时间内(注意是左闭右开区间)收到不少于K个赞,该帖就曾是"热帖"。
给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。
【输入格式】
第一行包含三个整数N、D和K。
以下N行每行一条日志,包含两个整数ts和id。
对于50%的数据,1 <= K <= N <= 1000
对于100%的数据,1 <= K <= N <= 100000 0 <= ts <= 100000 0 <= id <= 100000
【输出格式】
按从小到大的顺序输出热帖id。每个id一行。
【输入样例】
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
【输出样例】
1
3
蓝桥杯蓝桥杯我来啦!!
这道题应该算是比较简单的把,我可能对双指针情有独钟,所以又来写他的题解了=-=被双指针打击到了qaq
这道题很直观直接模拟即可。
把时间放入对应id的容器中,然后sort一下。
然后用尺取法的思想找一下有没有符合要求的id即可,
因为我们id本身遍历的时候就是从大到小遍历的,所以直接输出即可。
然后注意一下边界条件就可以啦,要在d的时间范围内,不能包括d,也就是只能小于d
双指针l1, l2走一遍就可以啦,遇到符合条件的break,成功继承zz思想哈哈哈。
这里有个地方就是不需要还原计数,因为根据尺取法的思想嘛,已经产生了固定满足要求的区间了,所以从第一个符合要求的地方开始,后面的全都符合大于d的要求,因为l1和l2都在++嘛。相反如果还原计数为0的话会比较麻烦。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> a[N];
vector<int> ans;
int main()
{
int n, d, k;
int s = 0;
cin >> n >> d >> k;
for (int i = 1; i <= n; i++)
{
int id, t;
cin >> t >> id;
a[id].push_back(t);
s = max(s, id);
}
for (int i = 0; i <= s; i++)
{
sort(a[i].begin(), a[i].end());
int l1 = 0, l2 = 0, r = a[i].size();
int flag = 0;
int cnt = 0;
while (l2 < r)
{
cnt++;
if (cnt >= k)
{
if (a[i][l2] - a[i][l1] < d)
{
flag = 1;
break;
}
else
{
l1++;
}
}
l2++;
}
if (flag)
{
ans.push_back(i);
}
}
int siz = ans.size();
for (int i = 0; i < siz; i++)
{
cout << ans[i] << endl;
}
return 0;
}