📜  门|门 CS 1999 |第 47 题(1)

📅  最后修改于: 2023-12-03 14:58:35.425000             🧑  作者: Mango

题目简介

题目描述:

现在有N扇门,编号从1~N,开始时所有的门都关闭着。有M个人,每个人都会按照一定的顺序来走这些门,具体地,第i个人会从门Ai开始,然后每次都跳到编号为当前门编号±Ai的门(其中+表示向右跳,向左跳就是-),直到走到一个关着的门,然后他会把这扇门打开,接着从这扇门出发继续上述行动。当然,如果他跳到了编号不存在的门上,那么他就从这个编号反弹回来继续上述行动(例如,他站在1号门,但他要跳到0号门,那么他会从0号门反弹回来,接着他会跳到2号门)。现在请你编写一个程序,来求出最终哪些门被打开了。

输入格式:

第一行包含两个整数N和M。

接下来M行,每行包含一个整数Ai,表示第i个人的起始门编号。

输出格式:

输出N个数,用空格隔开,表示每扇门是否被打开。其中1表示此门被打开,0表示此门仍然关闭着。

数据范围:

$1\leq N, M\leq 50000$ $1\leq Ai\leq 10000$

示例:

输入:

10 2
2
9

输出:

1 0 1 0 0 0 0 0 1 0

解题思路

这道题目要我们求最终哪些门被打开了,我们不妨先暴力枚举一下每扇门,看看他们会不会被打开。

具体来说,我们可以从每扇门出发模拟一下整个过程,看看最终他们是否被打开。

又因为总共有M个人,每个人最多会打开N扇门,时间复杂度肯定是超时的,所以我们需要想办法避免重复计算。

我们注意到,如果有两个人从同一扇门出发,那么他们可以完成完全相同的操作,所以我们可以将这些人看做一个整体,只需要从其中的一人出发,即可完成整体的操作。

在这个基础上,我们可以对人进行分类,将他们分为若干类,每类中的人出发的初始门相同,那么这些人就可以看做一个整体,同样只需要从其中一个人出发,即可完成整体的操作。

那么问题来了,如何判断两个人是否在同一类中呢?我们可以从代码实现的角度考虑这个问题。

我们首先给每一个人一个编号,而人与人之间的关系可以看做一个图(Graph),每个人与其他人之间都有一条边,表示他们可以相互到达。如果两个人在同一个连通分量(Connected Component)中,那么他们就在同一类中。

具体来说,对于每个人,我们可以模拟一遍从他出发打开的所有门,可以记录下每扇门最早被哪个人打开,如果之后有其他的人也来打开同一扇门,那么他就可以与之前打开这扇门的人归为同一个连通分量(如果他们未被打开),这样我们就可以快速地将所有的人归类了。

有了上述分类的结果,我们就可以只选择每一类中的一个人,从他出发打开所有的门,然后循环遍历所有的门,看看哪些门被打开了即可。

代码实现需要建图,使用并查集维护连通分量,具体细节详见以下代码。