【题目链接】
ybt 1975:【16NOIP普及组】海港
洛谷 P2058 [NOIP2016 普及组] 海港
【题目考点】
1. 模拟
2. 队列
【解题思路】
解法1:设队列,每个人是队列中的一个元素
由于人数总和(即k的加和)最大为 3 ∗ 1 0 5 3*10^5 3∗105,可以把每个人作为一个元素保存在队列中。
设计数数组c,c[i]
表示第i国籍的人数。
设结构体Peo表示一个人,每个人包含属性:时间time、国籍nation。
t时刻有船到岸:
- 先将队列中所有到达时间time比当前时间t早86400以上的人出队。每出队1个人,该国籍的人数减1。如果该国籍的人数变为0,则总国籍数量减1。
- 而后把该船上所有人加入到队列中,对于每个入队的人,这个人的国籍的人数加1。如果该国籍的人数从0变为1,则总国籍数量加1。
每次有船到岸,就输出一下国籍总数。
解法2:设队列,每条船是队列中的一个元素
每条船为一个元素,包含属性vector类型的nation,保存所有人的国籍,以及time表示时间。
注意:nation必须设为长度可变的vector,这样可以节省空间。如果设为数组,则会内存超限。
t时刻有船到岸:
- 先将队列中所有到达时间time比当前时间t早86400以上的船出队。每出队1条船,遍历该船上的所有人,每人对应的国籍人数减1。如果该国籍的人数变为0,则总国籍数量减1。
- 而后把该船加入到队列中,对于每个船上的人,这个人的国籍的人数加1。如果该国籍的人数从0变为1,则总国籍数量加1。
每次有船到岸,就输出一下国籍总数。
【题解代码】
解法1:使用队列,每个人是队列中的一个元素
#include <bits/stdc++.h>
using namespace std;
struct Peo
{int time, nation;Peo(){}Peo(int a, int b):time(a), nation(b){}
};
int c[100005];//c[i]:第i国籍人数
int main()
{queue<Peo> que;int n, t, k, x, ct = 0;//ct:总国籍数 cin >> n;for(int i = 1; i <= n; ++i){cin >> t >> k;while(que.empty() == false && que.front().time <= t-86400)//只要队列不空 {//到港时间que.front().time比当前时间t早86400秒以上的人都出队 int nat = que.front().nation;if(--c[nat] == 0)//nat国籍的人数减1,如果该国籍人数为0 ct--;//总国籍数量减少 que.pop(); }for(int j = 1; j <= k; ++j){cin >> x;if(++c[x] == 1)//x国籍人数增加,如果从0变为1 ct++;//总国籍人数增加 que.push(Peo(t, x)); }cout << ct << endl;}return 0;
}
解法2:设队列,每条船是队列中的一个元素
#include <bits/stdc++.h>
using namespace std;
struct Ship
{int time;vector<int> nation;
};
int c[100005];//c[i]:第i国籍人数
int main()
{queue<Ship> que;int n, t, k, x, ct = 0;//ct:总国籍数 cin >> n;for(int i = 1; i <= n; ++i){cin >> t >> k;while(que.empty() == false && que.front().time <= t-86400)//只要队列不空 {//到港时间que.front().time比当前时间t早86400秒以上的人都出队 for(int nat : que.front().nation){if(--c[nat] == 0)//nat国籍的人数减1,如果该国籍人数为0 ct--;//总国籍数量减少 }que.pop(); }Ship ship;ship.time = t;for(int j = 1; j <= k; ++j){cin >> x;ship.nation.push_back(x);if(++c[x] == 1)//x国籍人数增加,如果从0变为1 ct++;//总国籍人数增加 }que.push(ship);cout << ct << endl;}return 0;
}