并查集:方格染色

题目链接

方格染色

题目大意

Sam 和他的妹妹 Sara 有一个包含 n × m n \times m n×m 个方格的表格。他们想要将其中的每个方格都染成红色或蓝色。出于个人喜好,他们想要表格中每个 2 × 2 2 \times 2 2×2 的方形区域都包含奇数个( 1 个或 3 个)红色方格。例如,下面是一个合法的表格染色方案(R 代表红色,B 代表蓝色):

B B R B R
R B B B B
R R B R B

可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在 Sam 和 Sara 非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格依然满足他们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?

输入描述

输入的第一行包含三个整数 n , m , k n,m,k n,m,k 分别代表表格的行数,列数和已被染色的方格数目。

之后的 k k k 行描述已被染色的方格。其中第 i i i 行包含三个整数 x i , y i , c i x_i,y_i,c_i xi,yi,ci ,分别代表第 i i i 个已被染色的方格的行编号、列编号和颜色。 c i c_i ci为 1 表示方格被染成红色, c i c_i ci 为 0 表示方格被染成蓝色。

其中, 2 ⩽ n , m ⩽ 1 0 5 2 \leqslant n,m \leqslant 10^5 2n,m105 0 ⩽ k ⩽ 1 0 5 0 \leqslant k \leqslant 10^5 0k105 1 ⩽ x i ⩽ n 1 \leqslant x_i \leqslant n 1xin 1 ⩽ y i ⩽ m 1 \leqslant y_i \leqslant m 1yim, ∀ c i ∈ 0 , 1 \forall c_i \in {0,1} ci0,1

输出描述

输出一个整数,表示可能的染色方案数 w w w 对于 1 0 9 10^9 109 取模后得到的值。

输入输出样例

输入

3 4 3
2 2 1
1 2 0
2 3 1

输出

8

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

解题思路

异或运算+加权并查集

数据集量分析
2 ⩽ n , m ⩽ 1 0 5 2 \leqslant n,m \leqslant 10^5 2n,m105 0 ⩽ k ⩽ 1 0 5 0 \leqslant k \leqslant 10^5 0k105 1 ⩽ x i ⩽ n 1 \leqslant x_i \leqslant n 1xin 1 ⩽ y i ⩽ m 1 \leqslant y_i \leqslant m 1yim, ∀ c i ∈ 0 , 1 \forall c_i \in {0,1} ci0,1
n , m n,m n,m 的取值范围发现,如果利用矩阵存储整个表格,那么其所需内存空间将超出 128MB ,且时间复杂度也不允许。因此不能使用二维矩阵去表达这个表格。

关键思路

假设知道表格中第一行和第一列的染色情况,根据 2 × 2 2\times 2 2×2 区域只能有奇数个 c i = 1 c_{i}=1 ci=1 的要求,推导推导出整个表格的合法状态,因此,只需记录表格的第一行和第一列,就相当于记录了表格的整个状态。

异或运算:由于表格中 1 代表红色, 0 代表蓝色,从异或运算的角度出发。根据题意,可以推出满足要求的 2 × 2 2\times2 2×2 区域的异或和必为 1 。

1、设定此表格名称为 map ,下标从 1 开始。
2、假如当前已知map [ i ] [ j ] [i][j] [i][j] 被涂上颜色。然后在 i , j i,j i,j 范围内进行 2 × 2 2\times 2 2×2 异或和运算,发现除了 m a p [ 1 ] [ 1 ] map[1][1] map[1][1],map [ i ] [ 1 ] [i][1] [i][1],map [ 1 ] [ j ] [1][j] [1][j],map [ i ] [ j ] [i][j] [i][j] 四个“矩形端点”以外,其余的方格都参与了 2 次异或运算相抵消为 0 ,而唯独四个端点只参与了 1 次异或运算。因此, i , j i,j i,j 范围内所有点的异或和等价于这 4 个端点的异或和。

i , j i,j i,j 范围内所有点所有点的异或和:
通过计算表格能容纳的 2 × 2 2\times2 2×2 矩形框数量来求解
解释:每个 2 × 2 2\times2 2×2 矩形框的异或和都是 1 ,因此如果有偶数个矩形框,那么表格中点的异或和就是 0 ,否则,异或和是 1 。)
推导可以得出,仅当 i , j i,j ij 均为偶数时,矩形框的个数 ( i − 1 ) × ( j − 1 ) (i-1)\times(j-1) (i1)×(j1) 才为奇数,此时异或和为 1 。

由 4 端点异或和和表格异或和的等价关系和上述推导,可以得出如下式子:
m a p [ 1 ] [ 1 ]    x o r    m a p [ 1 ] [ j ]    x o r    m a p [ i ] [ 1 ]    x o r    m a p [ i ] [ j ]    = ( i % 2 = 0    a n d    j % 2 = 0 ) {\rm map}[1][1]\; xor \;{\rm map}[1][j]\; xor\;{\rm map}[i][1]\;xor\;{\rm map}[i][j]\;=(i\%2=0\; and\; j\%2=0) map[1][1]xormap[1][j]xormap[i][1]xormap[i][j]=(i%2=0andj%2=0)
即等价于
m a p [ 1 ] [ j ]    x o r    m a p [ i ] [ 1 ] = ( i % 2 = 0    a n d    j % 2 = 0 )    x o r    m a p [ 1 ] [ 1 ]    x o r    m a p [ i ] [ j ] {\rm map}[1][j]\; xor \;{\rm map}[i][1]=(i\%2=0\; and\; j\%2=0)\;xor\;{\rm map}[1][1]\; xor\;{\rm map}[i][j] map[1][j]xormap[i][1]=(i%2=0andj%2=0)xormap[1][1]xormap[i][j]

因此可以枚举 map [ 1 ] [ 1 ] [1][1] [1][1],通过加权并查集把所有有限制关系的点并到一起,通过存与根的关系来确定一个集合内两点间的关系。这样即可推出第一行和第一列之间的点的限制(相等或不等),要注意判不合法的状态。

最后的方案数就是 2 s e t _ n u m − 1 2^{set\_num-1} 2set_num1

reference:https://blog.csdn.net/qq_35320178/article/details/99672268

AC Code

Python3

# -*- coding: utf-8 -*-
# @Author : BYW-yuwei
# @Software: python3.8.6
M=int(1e6+5)
MOD=int(1e9)                            #取余数的数
x_idx=[0] ; y_idx=[0] ; color=[0]
father=[0]*M; d=[0]*M

def init(lim:int):                      #加权并查集初始化模板init
    for i in range(1,lim+1):
        father[i]=i ; d[i]=0
def get_father(x:int):                  #并查集组合的合并,权重数组保存异或值
    if x==father[x]:return x
    f=get_father(father[x])
    d[x]^=d[father[x]]
    father[x]=f
    return f

def mul(a:int,b:int):                   #快速幂运算模板mul(x,y)-->pow(x,y)                  
    ans=1
    while b:
        if b&1:ans=(ans*a)%MOD
        a=(a*a)%MOD
        b>>=1
    return ans
def solve(op:int):
    init(n+m)
    father[n+1]=1
    global k
    for i in range(1,k+1):
        if x_idx[i]==1 and y_idx[i]==1:continue  #(1,1)点无需再次判断
        temp=((x_idx[i]%2==0) and (y_idx[i]%2==0))^color[i]^op
        a=get_father(x_idx[i]) ; b=get_father(y_idx[i]+n)
        res=d[x_idx[i]]^d[y_idx[i]+n]^temp
        if a==b and res:return 0
        father[a]=b
        d[a]^=res
    cnt=0
    for i in range(1,n+m+1):
        if father[i]==i:cnt+=1
    return mul(2,cnt-1)

if __name__=='__main__':
    n,m,k=map(int,input().split())
    flag=-1
    for i in range(k):
        idx,idy,col=map(int,input().split())
        x_idx.append(idx);y_idx.append(idy);color.append(col)
    for i in range(1,k+1):
        if (x_idx[i]==1) and (y_idx[i]==1):flag=color[i]
    if flag==0:
        print(solve(0))
    elif flag==1:
        print(solve(1))
    else:
        print((solve(0)+solve(1))%MOD)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是雨玮a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值