蓝桥杯省赛日志统计

标题:日志统计

小明维护着一个程序员论坛。现在他收集了一份"点赞"日志,日志共有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

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include
不能通过工程设置而省略常用头文件。

提交程序时,注意选择所期望的语言类型和编译器类型。

我的做法是用尺取法结合STL会大大降低复杂度
首先对出现的时刻进行排序,然后用i,j维护一段区间,当区间对度小于D时j向后推动增大区间长度,否则i就向后推动减小区间长度,当区间满足条件时可以对这一段区间的时刻每个帖子的点赞数量进行一个计数,然后判断是否存在热帖

利用set的去重和排序的特性处理起来会更加方便

#include<cstdio>
#include<iostream>
#include<set>
#include<vector>
#include<map>
using namespace std;
set<int> t;//临时存放时刻
int time[100000];//	存放出现的时刻
vector<int> ve[100000];//存放每个时刻点赞的帖子编号 
set<int> heat;//存放热帖 
int N,D,K; 
void check(int x,int y){
	map<int,int> mp;//帖子计数器
	for(int i=x;i<=y;i++){
		int q = time[i];//当前时刻 
		for(int i=0;i<ve[q].size();i++){//遍历这个时刻点赞的帖子 
			mp[ve[q][i]]++;
			if(mp[ve[q][i]]>=K){//如果出现了热帖 
				heat.insert(ve[q][i]);//存下热帖编号 
			}
		}
	} 
}
int main(){
	cin>>N>>D>>K;
	for(int i=0;i<N;i++){
		int x,y; 
		cin>>x>>y;
		t.insert(x);//统计出现的时间
		ve[x].push_back(y);//x时刻点赞了y 
	}
	int con=0;
	for(set<int> :: iterator it=t.begin();it!=t.end();it++){
		time[con++]=*it;//将出现的时刻存入time方便执行尺取法 
	}
	int i=0,j=0;//指向第一个数
	while(i<=j&&j<con){
		if(time[j]-time[i]<D){//在规定区间内 
			check(i,j);//找出区间中的热帖 
			j++;//继续增大区间 
		}else{//不在规定区间内 
			i++;//左指针右移减小区间 
		}
	} 
	for(set<int>::iterator it=heat.begin();it!=heat.end();it++){
		cout<<*it<<" ";
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值