首先我们需要求出最长的时间段,然后将其划分为n个D长度的区间段,如果id在ts时刻在D区间段内 ,那么d的点赞量就加加,如果点赞量不小于k,那么我们就将其标记为热点。
最后我们遍历所有的id,看是否被标记过如果被标记过就输出
#include <bits/stdc++.h>
#define ts first
#define id second
using namespace std;
const int N = 1e5+10;
typedef pair<int,int> PII;
PII logs[N];
bool hot[N];
int cnt[N];
int n,d,k;
int main(){
scanf("%d%d%d",&n,&d,&k);
int maxt = 0;
for(int i = 0;i<n;i++)
{
scanf("%d%d",&logs[i].ts,&logs[i].id);
maxt = max(logs[i].ts,maxt);
}
//枚举n个id在 所有时刻的 点赞量
for(int time = 0;time <= maxt; time++) //从0时刻枚举到最大时刻
{
memset(cnt,0,sizeof(cnt)); //每个id的点赞量都要重置,重新计数
for(int i = 1;i<=n;i++) //n个id
{
int t = logs[i].ts;
int id = logs[i].id;
//只有从[time,time+d)时间段内 id收到的点赞量才会1被考虑 因time从0开始,所以右边是开区间
if( t>=time && t <time+d) //如果是在d时刻内 id 点赞量 大于k 就是热帖
cnt[id]++;
//每次加完就判断一下点赞量是否不小于K
if(cnt[id] >= k)
hot[id] = true;
}
}
//对于每个id,如果是热帖就输出编号
for(int id = 0;id<=100000;id++) //id最大个数1e5
if(hot[id]) printf("%d\n",id);
}
两层循环,n最大1e5,中间还划分了D区间,D的最大范围是1e4,因此最少也是1e9,时间复杂度就是O(n+D)
优化
比如当d是2 的时候,那么[0,2]和[1,3]时间段都是大于d的时间段,但是中间重复的部分:
因此我们可以对重复部分·不用再计算,这样的话就可以只遍历一次,时间复杂度是O(n):
code
在用双指针算法的时候我们需要排个序,保证其3具有单调性
#include <bits/stdc++.h>
#define ts first
#define id second
using namespace std;
const int N = 1e5 + 10;
typedef pair<int, int> PII;
PII logs[N];
bool hot[N];
int cnt[N];
int n, d, k;
int main() {
scanf("%d%d%d", &n, &d, &k);
int maxt = 0;
for (int i = 0; i < n; i++)
{
scanf("%d%d", &logs[i].ts, &logs[i].id);
}
sort(logs,logs+n);
for(int i=0,j=0;i<n;i++)
{
int t=logs[i].ts;
int id=logs[i].id;
cnt[id]++;
while(logs[i].ts-logs[j].ts>=d)
{
cnt[logs[j].id]--; //去掉开头
j++; //加上结尾
}
if(cnt[id]>=k)hot[id]=true;
}
//对于每个id,如果是热帖就输出编号
for (int i = 0; i <= 100000; i++) //id最大个数1e5
if (hot[i]) printf("%d\n", i);
return 0;
}