1095 Cars on Campus (30 分)
Zhejiang University has 8 campuses and a lot of gates. From each gate we can collect the in/out times and the plate numbers of the cars crossing the gate. Now with all the information available, you are supposed to tell, at any specific time point, the number of cars parking on campus, and at the end of the day find the cars that have parked for the longest time period.
Input Specification:
Each input file contains one test case. Each case starts with two positive integers N (≤104), the number of records, and K (≤8×104) the number of queries. Then N lines follow, each gives a record in the format:
plate_number hh:mm:ss status
where plate_number
is a string of 7 English capital letters or 1-digit numbers; hh:mm:ss
represents the time point in a day by hour:minute:second, with the earliest time being 00:00:00
and the latest 23:59:59
; and status
is either in
or out
.
Note that all times will be within a single day. Each in
record is paired with the chronologically next record for the same car provided it is an out
record. Any in
records that are not paired with an out
record are ignored, as are out
records not paired with an in
record. It is guaranteed that at least one car is well paired in the input, and no car is both in
and out
at the same moment. Times are recorded using a 24-hour clock.
Then K lines of queries follow, each gives a time point in the format hh:mm:ss
. Note: the queries are given in ascending order of the times.
Output Specification:
For each query, output in a line the total number of cars parking on campus. The last line of output is supposed to give the plate number of the car that has parked for the longest time period, and the corresponding time length. If such a car is not unique, then output all of their plate numbers in a line in alphabetical order, separated by a space.
Sample Input:
16 7
JH007BD 18:00:01 in
ZD00001 11:30:08 out
DB8888A 13:00:00 out
ZA3Q625 23:59:50 out
ZA133CH 10:23:00 in
ZD00001 04:09:59 in
JH007BD 05:09:59 in
ZA3Q625 11:42:01 out
JH007BD 05:10:33 in
ZA3Q625 06:30:50 in
JH007BD 12:23:42 out
ZA3Q625 23:55:00 in
JH007BD 12:24:23 out
ZA133CH 17:11:22 out
JH007BD 18:07:01 out
DB8888A 06:30:50 in
05:10:00
06:30:50
11:00:00
12:23:42
14:00:00
18:00:00
23:59:00
Sample Output:
1
4
5
2
1
0
1
JH007BD ZD00001 07:20:09
题意易错点:
最后一行输出的总时间是车辆累计停放的总时间,不是一次in-out的时间间隔
解题提示:
1.时间转换为s,方便许多(输出也方便 这是个常用技巧)
2.先删除垃圾记录,这很重要,不然后面的逻辑过于复杂,不仅易错,而且容易超时
删除垃圾记录的方式关键点:按车牌号一级排序,时间二级排序
删除垃圾数据后剩下的都是匹配的数据,再按时间排次序,in、out逻辑就简单了,直接一个int变量++ --即可(一次sort 和两次sort时间是一样,不会影响时间复杂度)
3.很重要,也很容易看出的一点,查询时间升序,因此查过的不必在查,每次查询在上次的基础上累加即可
4.最后,输入的数据有太多,cin会超时,将录入数据那块改成scanf
本题做30分答题就是逻辑乱,理得对好做,理得不好容易卡死,慢慢打断点很耗时间,做这种题脑子一定要清醒
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<map>
using namespace std;
const int maxn = 10010;
struct Car
{
string id, statue;
int time;
}all[maxn],valid[maxn];//输入的总记录数 和 合法的记录数
int timeToInt(int hh,int mm,int ss) {
return hh * 3600 + mm * 60 + ss;
}
//去掉垃圾数据用 车牌号一级排序 时间二级排序
bool compare1(Car a,Car b) {
if (a.id != b.id) return a.id < b.id;
return a.time < b.time;
}
//正真模拟in-out时的排序
bool compare2(Car a, Car b) {
return a.time < b.time;
}
int main() {
freopen("in.txt","r",stdin);
int N, K, hh, mm, ss;
char c;
char id[20], statue[10];
cin >> N >> K;
for (int i = 0;i < N;i++) {
scanf("%s %d:%d:%d %s", id,&hh,&mm,&ss,statue);
//cin >> all[i].id >> hh >> c >> mm >> c >> ss >> all[i].statue;
all[i].time = timeToInt(hh,mm,ss);
all[i].id = id,all[i].statue = statue;
}
sort(all,all+N,compare1);
//去掉垃圾记录 筛选有效记录
int num = 0;
map<string,int> partTime;
int MaxTime = 0;//最长时间
//注意是N-1 不是N因为下面是i+1
for (int i = 0;i < N-1;i++) {//最长时间在此处顺便算比较合适 因为此处正好是in-out的配对
if (all[i].id == all[i + 1].id&&all[i].statue == "in"&&all[i + 1].statue == "out") {
valid[num++] = all[i];valid[num++] = all[i + 1];
//顺便求累计时差
int dTime = all[i + 1].time - all[i].time;
if (partTime.count(all[i].id) == 0) {
partTime[all[i].id] = 0;
}
partTime[all[i].id] += dTime;
//和partTime[all[i].id]比不是和dTime比
MaxTime = max(MaxTime, partTime[all[i].id]);//维护最长时间 最后遍历一遍,输出所有最长时间即可 因为已经是车牌号字母序 重前往后遍历输出就好了
i++;//相当于遍历到i+1了 千万放到最后 因为上面用到i了
}//否则就是非法数据直接不理睬 丢弃
}
sort(valid, valid + num,compare2);
int nowNum = 0, step=0;//step遍历的指针 指向当前遍历的那辆车
while (K--) {
cin >> hh >> c >> mm >> c >> ss;
int nowTime = timeToInt(hh,mm,ss);
while (step<num&&valid[step].time<=nowTime){//注意,临界时间点 进了算进,出了算出
if(valid[step].statue=="in") nowNum++;
else nowNum--;//因为去重了 所以现在很简单
step++;//遍历的指针+1
}
cout << nowNum << endl;
}
for (map<string, int>::iterator it = partTime.begin();it != partTime.end();it++) {
if (it->second == MaxTime) cout << it->first << " ";
}
int h = MaxTime / 3600;
int m = (MaxTime - h * 3600) / 60;
int s = MaxTime % 60;
printf("%02d:%02d:%02d",h,m,s);
return 0;
}
整理下就很短了:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10010;
struct Car
{
string id, statue;
int time;
}all[maxn],valid[maxn];//输入的总记录数 和 合法的记录数
int timeToInt(int hh,int mm,int ss) {
return hh * 3600 + mm * 60 + ss;
}
bool compare1(Car a,Car b) {
if (a.id != b.id) return a.id < b.id;
return a.time < b.time;
}
bool compare2(Car a, Car b) {return a.time < b.time;}
int main() {
int N, K, hh, mm, ss;
char c,id[20], statue[10];
cin >> N >> K;
for (int i = 0;i < N;i++) {
scanf("%s %d:%d:%d %s", id,&hh,&mm,&ss,statue);
all[i].time = timeToInt(hh,mm,ss);
all[i].id = id,all[i].statue = statue;
}
sort(all,all+N,compare1);
int num = 0;
map<string,int> partTime;
int MaxTime = 0;//最长时间
for (int i = 0;i < N-1;i++) {//最长时间在此处顺便算比较合适 因为此处正好是in-out的配对
if (all[i].id == all[i + 1].id&&all[i].statue == "in"&&all[i + 1].statue == "out") {
valid[num++] = all[i];valid[num++] = all[i + 1];
int dTime = all[i + 1].time - all[i].time;
if (partTime.count(all[i].id) == 0) partTime[all[i].id] = 0;
partTime[all[i].id] += dTime;
MaxTime = max(MaxTime, partTime[all[i].id]);//维护最长时间 最后遍历一遍,输出所有最长时间即可 因为已经是车牌号字母序 重前往后遍历输出就好了
i++;//相当于遍历到i+1了 千万放到最后 因为上面用到i了
}//否则就是非法数据直接不理睬 丢弃
}
sort(valid, valid + num,compare2);
int nowNum = 0, step=0;//step遍历的指针 指向当前遍历的那辆车
while (K--) {
cin >> hh >> c >> mm >> c >> ss;
int nowTime = timeToInt(hh,mm,ss);
while (step<num&&valid[step].time<=nowTime){//注意,临界时间点 进了算进,出了算出
if(valid[step].statue=="in") nowNum++;
else nowNum--;//因为去重了 所以现在很简单
step++;//遍历的指针+1
}
cout << nowNum << endl;
}
for (map<string, int>::iterator it = partTime.begin();it != partTime.end();it++) {
if (it->second == MaxTime) cout << it->first << " ";
}
printf("%02d:%02d:%02d",MaxTime / 3600,(MaxTime - MaxTime / 3600 * 3600) / 60,MaxTime % 60);
return 0;
}