持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
题目描述
小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有行。其中每一行的格式是:
表示在 时刻编号 的帖子收到一个"赞"。
现在小明想统计有哪些帖子曾经是"热帖"。如果一个帖子曾在任意一个长度为 的时间段内收到不少于 个赞,小明就认为这个帖子曾是"热帖"。
具体来说,如果存在某个时刻 满足该帖在 这段时间内(注意是左闭右开区间)收到不少于 个赞,该帖就曾是"热帖"。
给定日志,请你帮助小明统计出所有曾是"热帖"的帖子编号。
输入描述
输入格式:
第一行包含三个整数 ,,。
以下 行每行一条日志,包含两个整数 和 。 其中,,,
输出描述
按从小到大的顺序输出热帖 。每个 一行
输入输出样例
示例
输入
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
输出
1
3
看到这道题我们第一想法是枚举长度个区间,挨个判断里面的是否满足点赞数量,但是很显然,这样做的时间复杂度是,会超时,所以我们要考虑优化,我们注意到输入是乱序的,因此我们应该想到先对进行排序,因此开一个结构体,存时间和序号,先按照从小到大的顺序排序,从第一个时间段开始遍历。 我们注意到因为是连续时间段,所以我们可以维护一个区间(即 ),及时更新区间里面的和这个所对应赞的数量,如果数量,那就将这个存入一个数组,最后跑完条日志,将排序,输出。
由以上步骤我们可以知道,遍历可以做到单调,就是不走回头路,我们可以通过双指针算法来实现,我们可以用来维护这个区间。 贴上代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <iomanip>
#define ll long long
#define AC return
#define Please 0
using namespace std;
const int N=100010;
const double eps=1e-9;
typedef pair<int,int>PII;
typedef unsigned long long ull;
int n,d,k;
bool flag[N];//判断id是否出现过
inline int read(){//快读
int x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
AC x*f;
}
int ans[N],cnt=0;
struct mes{
int ts,id;
}a[N];
bool cmp(mes x,mes y){//排序函数
return x.ts<y.ts;
if(x.ts==y.ts){
return x.id<=y.id;
}
}
int main(){
n=read(),d=read(),k=read();//n评论 d时间范围 k条点赞
for(int i=1;i<=n;i++){
cin>>a[i].ts>>a[i].id;
}
memset(flag,0,sizeof flag);
sort(a+1,a+n+1,cmp);
map<int,int>mp;
mp.clear();
for(int j=1,i=1;j<=n;j++){
while(a[j].ts-a[i].ts>=d){//这里一定要注意,先判断是否大于等于d
//否则可能会出现多加1的情况
mp[a[i].id]-=1;
if(mp[a[i].id]==0){
mp.erase(a[i].id);
}
i++;
}
mp[a[j].id]+=1;
if(mp[a[j].id]>=k && flag[a[j].id]==0){
ans[++cnt]=a[j].id;
flag[a[j].id]=1;
}
}
sort(ans+1,ans+cnt+1);
for(int i=1;i<=cnt;i++){
cout<<ans[i]<<endl;
}
AC Please;
}
希望能帮到大家()