- 吴浩宁 的博客
海港
- @ 2024-9-22 12:08:18
【题意总结】
他按照时间记录下了到达海港的每一艘船只情况;对于第 艘到达的船,他记录了这艘船到达的时间 (单位:秒),船上的乘客数 ,以及每名乘客的国籍 。
题目共输入 艘船的数据,每份数据中包含第 艘船的到达时间 、这艘船上搭载的乘客数量 以及船上每名乘客的国籍 。
要求输出的是在每一艘船到达港口时,计算前 24 个小时(86400秒)中(包含这一秒),所有到达港口的船上所有的乘客是来自多少个国家的。
抽象一点地说,这题会输入 条信息组,其中的第 组信息中会包含它的时间编号 、元素数量 以及每个元素的类别。要求输出 行,每行输出以 为起点向前 86400 秒内所有元素共有多少个类别。
简单地想想即可看出队列的结构:
前面输入的某个元素如果与当前输入的元素之间的时间差超过 86400 秒,那么这个元素就永远不会参与计算了,也就可以说被弹出了。
先输入的元素会被先弹出,明显的队列结构。
进一步能够想到滑动窗口,这题能够被看成一个以秒为单位的长度为 86400 的滑动窗口,只是要输出以每个输入的时间 为右端点的窗口中元素的类别之和即可。
【样例计算】
#1:
3
1 4 4 1 2 2
2 2 2 3
10 1 3
3
4
4
一共有 艘船。 第一艘:于第 秒到达海港,船上共有 名乘客。最近 小时内到达的船有:第一艘,这些船上共有 名乘客,来自国家:,共有 个不同的国家。
第二艘:于第 秒到达海港,船上共有 名乘客。最近 小时内到达的船有:第一艘、第二艘,这些船上共有 名乘客,来自国家:,共有 个不同的国家。
第三艘:于第 秒到达海港,船上共有 名乘客。最近 小时内到达的船有:第一艘、第二艘、第三艘,这些船上共有 名乘客,来自国家:,共有 个不同的国家。
#2
4
1 4 1 2 2 3
3 2 2 3
86401 2 3 4
86402 1 5
3
3
3
4
一共有 艘船。 第一艘:于第 秒到达海港,船上共有 名乘客。最近 小时内到达的船有:第一艘,这些船上共有 名乘客,来自国家:,共有 个不同的国家。
第二艘:于第 秒到达海港,船上共有 名乘客。最近 小时内到达的船有:第一艘、第二艘,这些船上共有 名乘客,来自国家:,共有 个不同的国家。
第三艘:于第 秒到达海港,船上共有 名乘客。最近 小时内到达的船有:第二艘、第三艘,这些船上共有 名乘客,来自国家:,共有 个不同的国家。
第四艘:于第 秒到达海港,船上共有 名乘客。最近 小时内到达的船有:第二艘、第三艘、第四艘,这些船上共有 名乘客,来自国家:,共有 个不同的国家。
思路
以每个人为单位,需要记录每个人的到达时间和国籍,所以先创建一个结构体 P ,再创建一个 P 类型的队列 peo ,用它来模拟滑动窗口的过程,再使用一个桶数组来记录每个国家有没有人。
但是这个方法会有两层循环,在最坏情况下会有 的时间复杂度,明显的 Time Exceeded。
那么可不可以在一层循环的基础上动态更新计数变量 sum 呢?
更新条件:
当桶数组中的某一项 的值从 变成 时,代表又出现了一个新的国籍,sum++。
当桶数组中的某一项 的值从 变成 时,代表这 个小时内出现的国籍数量又减少了一个,sum--。
示例代码
#include <bits/stdc++.h>
using namespace std;
struct P{
int time,ne;
};
const int N=1e5+5;
int n,k,t,x,sum,cnt[N];
queue<P> peo;
int main(){
freopen("port.in","r",stdin);
freopen("port.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>t>>k;
for(int j=1;j<=k;j++){
cin>>x;
peo.push({t,x});
cnt[x]++;
if(cnt[x]==1) sum++;
}
while(t-86400>=peo.front().time){
cnt[peo.front().ne]--;
if(cnt[peo.front().ne]==0) sum--;
peo.pop();
}
cout<<sum<<'\n';
}
return 0;
}