在写之前先发发牢骚(),不想看可以跳过一下,我把csdn当日记本()。讲道理我一个月没更新了,那为啥不更新呢?是我没写题吗?不是,有些,只不过我习惯一个专题刷差不多了再去写csdn,然后。。。。线段树和树状数组现在都还没写完,所以先往后跳了,加上逆天课内排课(指三门数学)根本没啥时间写算法,所以一直拖着,还好最近蓝桥杯马上要比赛了,我也是直接课内放弃了,先把基础学了。不然这300不如吃顿火锅。之后应该会回复更新吧(大概),也有可能考完蓝桥杯就期末月彻底死亡了。得,看题吧。
先贴个题目:
以及原题链接:1238. 日志统计 - AcWing题库https://www.acwing.com/problem/content/1240/
然后讲讲思路 ,这题刚开始觉得直接前缀和就好了,然后开了个1e5*1e5的数组,毫不意外的爆了,于是思考怎么办,第一个优化思路是只开一个一维数组存时间节点内的点赞情况,而所有没点赞的情况统一放到有点赞的时候处理,这个思路借鉴AcWing 1241. 外卖店优先级 解题思路及代码-CSDN博客这个题目的思路,然后我们可以发现,这题还不用思考中间经过了多少时间去做减法,只需要确定时间终点T,看有没有点赞记录在T-D之外的,把他删除就好,所以就类似一个滑动窗口,随着时间段终点(拿起点处理也可以)的推移,不断有新的点赞记录进来,也不断有旧的点赞记录被删除。然后这就是全部思路,来看看代码。
#include <iostream>
#include <algorithm>
#define ts first
#define id second
using namespace std;
const int N = 1e5 + 10;
pair<int, int> d[N];
int cnt[N];
bool yx[N];
int main()
{
int n, D, k;
cin >> n >> D >> k;
for (int i = 0; i < n; ++i)
scanf("%d%d", &d[i].ts, &d[i].id);
sort(d, d + n);
for (int i = 0, j = 0; i < n; ++i)
{
cnt[d[i].id]++;
while (d[i].ts - d[j].ts >= D)
{
cnt[d[j].id]--;
j++;
}
if (cnt[d[i].id] >= k)
{
yx[d[i].id] = true;
}
}
int ans = 0;
for (int i = 0; i < N; ++i)
if (yx[i])
cout << i << endl;
return 0;
}
注意这个while,有可能在这次处理点赞记录时,有不止一个点赞记录需要被删除。这是一个双指针算法,可以理解成i在前面推移,j在后面追(每次追到能进入到时间段为止)。然后注意可以写一个pair存点赞记录,然后需要根据时间顺序排序处理,不然没法保证时间是按顺序被处理的。
by————2024.4.6刷题记录