P2058 [NOIP2016 普及组] 海港 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
小 K 是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客。
小 K 对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况;对于第 i 艘到达的船,他记录了这艘船到达的时间 ti (单位:秒),船上的乘客数 ki,以及每名乘客的国籍 xi,1,xi,2,…,xi,k。
小K统计了 n 艘船的信息,希望你帮忙计算出以每一艘船到达时间为止的 24 小时(24 小时 =86400 秒)内所有乘船到达的乘客来自多少个不同的国家。
形式化地讲,你需要计算 n 条信息。对于输出的第 i 条信息,你需要统计满足 ti−86400<tp≤ti 的船只 p,在所有的 xp , j 中,总共有多少个不同的数。
输入格式
第一行输入一个正整数 n,表示小 K 统计了 n 艘船的信息。
接下来 n 行,每行描述一艘船的信息:前两个整数 ti 和 ki 分别表示这艘船到达海港的时间和船上的乘客数量,接下来 ki 个整数xi , j 表示船上乘客的国籍。
保证输入的 ti 是递增的,单位是秒;表示从小K第一次上班开始计时,这艘船在第 ti 秒到达海港。
输出格式
输出 n 行,第 i 行输出一个整数表示第 i 艘船到达后的统计信息。
输入:
3
1 4 4 1 2 2
2 2 2 3
10 1 3
输出:
3
4
4
思路:
统计每一艘船到达时,前24小时内的国家总数,最简单的方法就是输入的时候就进行判断,用类似于桶排序的方法存放每个国家的人数,这样损失空间换取时间,一旦有新的国家的人到达判断一手就行。
40昏:
#include<bits/stdc++.h>
using namespace std;
int n;
int cou[100005];
//hash表 桶 (?)
int main()
{
cin>>n;
long long cnt=0;
while(n--){
long long t,k,x;
cin>>t>>k;
//时间没有考虑
while(k--){
cin>>x;
if(cou[x]==0) cnt++;
cou[x]++;
}
cout<<cnt<<endl;
}
return 0;
}
有40分的原因就是有些数据的时间差并没有超过86400s,也就是说,我们没有考虑时间。
100昏:
想要AC就需要借助数据结构 队列 queue 。上述的代码的思路延用,只是需要再多考虑一个时间的问题。以新到达的船的时间为起点,向左搜索到<t-86400的那一艘船,并且只统计属于该时间段内的船。但是,这样的需要的时间非常大,t有1e9级。我们注意到:“保证输入的 ti 是递增的”说明我们在剔除不属于该时间段的船的时候,是按照输入时候的顺序踢出的,也就是:先进先出!
队列中存放每一个人的信息,如果队首的人的时间t已经不再属于我们需要统计的时间段内就pop,当然pop之前需要对这个人的国家数进行删除。
#include<bits/stdc++.h>
using namespace std;
int n;
int cou[100005];//存放所有国家de人数 类似于 桶
struct Person{
int country;
int t;
};
queue<Person> q;//存放在时间段内的所有人
int main()
{
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
int t,k;
cin>>t>>k;
while(!q.empty()){
//栈也好 队列也好 在查询元素、弹出元素前都要先判断empty
Person temp=q.front();
if(temp.t+86400<=t){
//队列顶部的那一个人不再时间范围内
//踢出队列
cou[temp.country]--;
if(cou[temp.country]==0) ans--;
//说明有一个国家的人数已经减到0了,总数--
q.pop();
}
else break;
}
//存放新的数据 并进行输出
int x;
for(int j=1;j<=k;j++){
cin>>x;
Person temp;
temp.t=t;temp.country=x;
q.push(temp);
cou[x]++;
if(cou[x]==1) ans++;
}
cout<<ans<<endl;
}
return 0;
}
总结:使用栈或者是队列等数据结构最重要的是想出数据的进出方式,以及容器到底存放什么数据!