P2058 海港
原题链接 https://www.luogu.org/problemnew/show/P2058
这道题昨天qyf大佬刚给我们讲了一下,所以今天就把它做啦!
qyf大佬的思路和我的是一样的(其实是借鉴了qyf大佬的思路),但是由于他是用的指针+动态数组来实现的,这搞得我有些懵,今天仔细一想(没看题解QwQ~)发现可以用队列来实现,所以为了记录这个思路,写了一篇队列的博客。
想看指针+动态数组实现的同学们戳这里,还送屠龙宝刀哦~ 传送门
首先这是一道模拟题,思路也很简单:
1. 题目中要求有多少个不同的国籍,所以我们先开一个 nat 数组类似于桶排那样来记录第 i 个国籍有多少人;
2. 对于当前到来的船,我们可以将这艘船的所有乘客全入队(注意是乘客!),他们维护两个信息:到来的时间 t 和国籍 nation;
3. 我们要统计 ( ti - 86400,ti ] ,所以我们要有一个 delete 操作将队列里所有 t <= ti - 86400 的乘客弹出队列,同时注意对应的国籍人数减一;
4. 考虑到 nat 记录的是国籍的人数,那么我们可以想到:若 nat [ i ] 从一个大于0的数减到了0,那么不就说明这个国籍就没有了?此时的国籍数kind就要 -1;同理若 nat [ i ] 从0加了一个正数,说明该国籍出现了,那么此时的国籍数kind 就要 +1;
5. 然后我们输出kind 即可;
代码如下:
#include<iostream> #include<cstdio> #include<queue> using namespace std; int read() { char ch=getchar(); int a=0,x=1; while(ch<'0'||ch>'9') { if(ch=='-') x=-x; ch=getchar(); } while(ch>='0'&&ch<='9') { a=(a<<3)+(a<<1)+(ch-'0'); ch=getchar(); } return a*x; } struct people { int t,nation; }a[100001]; queue<people> q; int n,num,guo,kind,t[100001],vis[100001]; void delet(int tim) { people f=q.front(); //因为我们是按照时间顺序来将乘客入队的,所以队首乘客的t一定最小 while(f.t<=tim) { q.pop(); vis[f.nation]--; //对应国籍人数减一 if(vis[f.nation]==0) kind--; //国籍人数减到0,说明这种国籍消失,国籍数kind减一 f=q.front(); } return ; } int main() { n=read(); //n艘船 for(int i=1;i<=n;i++) { t[i]=read(); //这一艘船到来的时间 num=read(); //乘客人数 for(int j=1;j<=num;j++) { guo=read(); //所属国籍 if(!vis[guo]) kind++; //如果之前这种国籍的人数为0,说明多了一种国籍 vis[guo]++; q.push((people){t[i],guo});//入队,维护时间t 和国籍nation } delet(t[i]-86400); //删除t[i]-86400以前的船,注意要放在入队操作之后 printf("%d\n",kind); } return 0; }