链接:https://ac.nowcoder.com/acm/contest/9981/D
题目
牛牛拿到了一个n*n的方阵,每个格子上面有一个数字:0或1
行和列的编号都是从0到n-1
现在牛牛每次操作可以点击一个写着1的格子,将这个格子所在的1连通块全部变成0。
牛牛想知道,自己有多少种不同的方案,可以把全部格子的1都变成0?
所谓连通块,是指方阵中的两个正方形共用一条边,即(x,y)和以下4个坐标的数是连通的:(x-1,y)、(x+1,y)、(x,y-1)、(x,y+1)
这个问题对于牛牛来说可能太简单了。于是他将这个问题变得更加复杂:
他会选择一个格子,将这个格子上的数字修改成1(如果本来就是1,那么不进行任何改变),再去考虑“点一成零”的方案数。
牛牛想知道,每次“将某个格子修改成1”之后,“把全部格子的1都变成0”的方案数量。
ps:请注意,每次“将某个格子修改成1”之后,状态会保留到接下来的询问。具体请参考样例描述。
由于方案数可能过大,请对1e9+7取模
思路
假设一共用 m 个 1 的连通块,每个块的大小为siz[i]
每个连通块的点击顺序随意,所以有n!中方案,每个连通块需要选择其中一个进行点击,所以总方案数为
考虑把 0 变成 1 的操作,分为四种情况:
如果本来就是 1 那么无事发生
单独的一个 1,就相当于多加了一个连通块
某个连通块变大
两个连通块连在了一起,即连通块总数先减二,再增加一个大的连通块
具体做法
用并查集进行统计,设初始结果为ans
情况 2 : ans = ans * (m+1) % mod
情况 4 : 假设是 x 和 y 两个连通块合并了 ans = (siz[x] + siz[y]) * ans / (m * siz[x] * siz[y])
(这个地方要用到费马小定理,如果模数mod是质数,那么一个数a的0乘法逆元就是a的(mod-2)次方)
情况 3 : 我的做法是,只要不是情况 1,就按情况 2 处理,然后扫描周边,检查是否会出现情况 4,在这个过程中,就会处理好这三种情况
代码
1 |
|
- 本文作者: 水蓝络合物
- 本文链接: https://miku39393939.github.io/2021/05/10/2021-02-21-niuke01_D/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!