J-数据时间?_2025牛客寒假算法基础集训营2 题解

链接:https://ac.nowcoder.com/acm/contest/95334/J
来源:牛客网

题目描述

牛可乐正在分析最近几个月用户登录牛客 APP 的情况,他所收集的数据由三个字段构成,分别为:user_id表示用户 ID,login_date表示登录日期,login_time表示登录时间
他想请你帮助他统计h年m月份通勤、午休、临睡这三个时段各有多少人登录过 APP。特别地,同一个人在同一时段多次登录视作一次。

在本题中,通勤时间段为 07:00:00-09:00:00和18:00:00-20:00:00;午休时间段为11:00:00-13:00:00;临睡时间段为 22:00:00-01:00:00。时间段均包含左右边界值。

输入描述:

1
2
3
4
5
第一行输入三个整数 n,h,m(1≦n≤105; 2000≦h≦2030; 1≦m≦12)代表你需要处理的数据总数目、查询的年份、查询的月份。 
此后n行,每行先输入一个整数 user_id (1≦user_id≦10^20)代表用户 ID;再输入一个 YYYY-MM-DD 模式的日期 login_date代表用户登录日期;最后输入一个 hh:mm:ss 模式的时间 login_time代表用户登录时间。

YYYY-MM-DD 模式的时间定义为:2000≦YYYY≦2030代表年份,1≦MM≦12代表月份,1≦DD≦31代表日期。日期遵照平闰年规则。
hh:mm:ss 模式的时间定义为:0≦hh≦23代表小时、0≦mm≦59代表分钟、0≦ss≦59代表秒。

输出描述:

1
在一行上输出三个整数代表通勤、午休、临睡三个时段的登录人次。注意,同一个人在同一时段多次登录视作一次。          

输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
13 2021 12
2 2021-11-08 20:00:00
2 2021-12-03 07:00:00
3 2021-12-03 11:00:00
3 2021-12-05 12:00:00
4 2024-11-08 20:00:00
2 2021-12-06 09:20:00
2 2021-12-06 18:20:00
2 2021-12-07 13:00:00
2 2021-12-31 22:00:00
3 2021-12-30 21:00:00
4 2021-12-30 00:50:00
4 2021-12-31 00:30:00
2 2021-11-09 17:00:00

输出

1
1 2 2

​ 示例2

输入

1
2
3
2 2025 1
1000 2024-12-31 23:59:59
1000 2025-01-01 00:00:00

输出

1
0 0 1

说明

1
先判定年份与月份,再判定时间。

​ 示例3

输入

1
2
3
2 2025 1
1 2025-01-23 00:00:00
1 2025-01-22 00:00:00

输出

1
0 0 1

说明

1
同一时间段不作重复计算。

题解

本题实际上不难,是一道模拟,但是可以灵活使用多种STL容器来让本题的代码实现非常简单。

首先为了统计每个人的登录次数,我们不需要把所有人的所有信息都记录下来之后再进行判断,而只需要在循环中的一次读入内判断完就可以了。

其次,题目中的要求“同一个人在同一时段多次登录视作一次”,理解成是自动去重,我们不难考虑到unordered_set容器,可以自动去重。

于是我们定义三个时间段的容器,分别存储在三个时间登录过APP的人数即可。

即每次insert账号,最后输出size()。

然后就是这几个时间。

首先是年份和月份,我们可以读入login_date之后使用sscanf函数和最开始读入的h和m进行比较,如果未通过就continue。

但是我们使用的是string进行读入,而sscanf函数只支持char[],该如何是好呢?

我们可以使用std::string 类的一个成员函数.c_str(),用于将 std::string 对象转换为 C 风格的字符串(即以 \0 结尾的字符数组)。

再之后就是login_time的问题了,我们注意到由于格式都一样,我们可以直接使用字典序进行比较来确定是否落在我们需要的时间里面。

也就是可以定义一个这样的函数

1
2
3
bool P(string time,string start,string end){
return time>=start&&time<=end;
}

如果落在我们需要的范围内就会返回true。

接下来如果只是这样暴力的if(P(login_time,"07:00:00","09:00:00")||P(login_time,"18:00:00","20:00:00"))当然也是可以的,但是我们可以有更好的选择,

我们注意到一个时间段由两个部分组成:开始和结束,这让我们不禁考虑到使用pair来存储一个时间段,而通勤时间和临睡时间由两个时间段组成,这样我们可以使用vector来存储pair,再使用based循环来解决问题。

1
2
3
4
// 定义时间段
vector<pair<string, string>> rushHours = {{"07:00:00", "09:00:00"}, {"18:00:00", "20:00:00"}};
vector<pair<string, string>> lunchHours = {{"11:00:00", "13:00:00"}};
vector<pair<string, string>> sleepHours = {{"22:00:00", "23:59:59"}, {"00:00:00", "01:00:00"}}; //记得拆分

最终的代码实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<bits/stdc++.h>
#include <unordered_set>
using namespace std;
const int maxn=1e5+10;
int n,h,m;
string user_id,login_date,login_time;
unordered_set<string> tongqing,wuxiu,lingshui;
bool P(string time,string s,string e){
return time>=s&&time<=e;
}
// 定义时间段
vector<pair<string, string>> rushHours = {{"07:00:00", "09:00:00"}, {"18:00:00", "20:00:00"}};
vector<pair<string, string>> lunchHours = {{"11:00:00", "13:00:00"}};
vector<pair<string, string>> sleepHours = {{"22:00:00", "23:59:59"}, {"00:00:00", "01:00:00"}};
int main(){
cin>>n>>h>>m;
for(int i=0;i<n;i++){
cin>>user_id>>login_date>>login_time;
int year,month;
sscanf(login_date.c_str(),"%d-%d",&year,&month);
if(year!=h||month!=m) continue;
for(const auto& x:rushHours){
if(P(login_time,x.first,x.second)){
tongqing.insert(user_id);
break;
}
}
for(const auto& x:lunchHours){
if(P(login_time,x.first,x.second)){
wuxiu.insert(user_id);
break;
}
}
for(const auto& x:sleepHours){
if(P(login_time,x.first,x.second)){
lingshui.insert(user_id);
break;
}
}
}
cout<<tongqing.size()<<' '<<wuxiu.size()<<' '<<lingshui.size()<<endl;
}

J-数据时间?_2025牛客寒假算法基础集训营2 题解
http://example.com/2025/01/24/J-数据时间?_2025牛客寒假算法基础集训营2 题解/
作者
Kiriao
发布于
2025年1月24日
许可协议