[Apio2011]方格染色

Time Limit: 20 Sec    Memory Limit: 256 MB

Description

Sam和他的妹妹Sara有一个包含n × m个方格的
表格。她们想要将其的每个方格都染成红色或蓝色。
出于个人喜好,他们想要表格中每个2 ×   2的方形区
域都包含奇数个(1 个或 3 个)红色方格。例如,右
图是一个合法的表格染色方案(在打印稿中,深色代
表蓝色,浅色代表红色) 。
可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara
非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格
仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?


Input

输入的第一行包含三个整数n, m和k,分别代表表格的行数、列数和已被染
色的方格数目。
之后的k行描述已被染色的方格。其中第 i行包含三个整数xi, yi和ci,分别
代表第 i 个已被染色的方格的行编号、列编号和颜色。ci为 1 表示方格被染成红
色,ci为 0表示方格被染成蓝色。

Output

输出一个整数,表示可能的染色方案数目 W 模 10^9得到的值。(也就是说,如果 W大于等于10^9,则输出 W被10^9除所得的余数)。

对于所有的测试数据,2 ≤ n, m ≤ 106
,0 ≤ k ≤ 10^6
,1 ≤ xi ≤ n,1 ≤ yi ≤ m。

Sample Input

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

Sample Output

8
 
 
题解:1.BFS 2.并查集(类似10年NOIP第三题)
 

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

假设这是一张4×4的表格。根据题意,任意一个2×2的格子内的四个数的异或值为1。所以A^B^E^F=1,B^F^C^G=1. 两式异或。则A^E^C^G=0. 同理,A^E^D^H=1. 

又,A^B^E^F=1, E^F^I^J=1. 所以A^B^I^J=0.

又,F^G^J^K=1,E^F^I^J=1,A^E^C^G=0. 所以,A^C^I^K=0.      (^符号表示异或运算)

综上,对于表格中的任意一个不在第一行且不在第一列的格子的颜色都由该格所在行与列的第一个数与左上角的数的异或值决定。即c[i,j]=c[1,j] xor c[i,1] xor c[1,1].

所以,当表格的第一行与第一列的值都固定后,整张表格就唯一确定了。

而左上角的格子颜色只有两种,所以我们可以枚举其颜色,然后每个格子就只由行首与列首两个格子决定了。

假设一开始表格的第一行和第一列都为零,则形如:

 

0

0

0

0

0

0

0

0

1

0

1

0

1

0

0

0

0

0

0

0

0

0

1

0

1

0

1

0

0

0

0

0

0

0

0

0

1

0

1

0

1

0

0

0

0

0

0

0

0

 

则对于每一个c[i,j],若i与j同为偶数时,它的颜色为1,则行列的首格的异或值为0,颜色为0,则行列的首格的异或值为1。若i与j不同时为偶数,它的颜色为1,则行列的首格的异或值为1,颜色为0,则行列的首格的异或值为0。

由此,对读入的每一个确定颜色的格子,都可以确定它的行列首格的关系(相同或不同;异或值为0或为1)。

操作时对于修改首行或首列的格子时,我的做法是建立一个数组记录每个节点的颜色,然后修改这个格子父亲的颜色,有冲突即无解。还有两个格子有同一个父亲,可是原关系与所给关系冲突也是无解的情况。

剩下的就是并查集的基本操作了。路径压缩时修改与父亲的关系。

如果输入给定了左上角的颜色,那么如果颜色为1,则将读入颜色全部取反做一遍,如果颜色为0,则只要做一遍,没有给出颜色则枚举颜色做两遍。将两次的方案数相加。

最后方案数的求法就是2的未被染色的集合个数的次方。。就是2^(未被染色的集合个数)。这是建立在有解的前提下的。。

 

AC CODE

 

//又臭又长。。。

 

program hy_2303;
const mo=1000000000;
var h,l,c,fa,co,re:array[1..1000000] of longint;
    p:array[1..1000000] of boolean;
    n,m,k,i,ans,tt:longint;
    flagg:boolean;
//============================================================================
function getfa(x:longint):longint;
begin
  if fa[x]=x then exit(x);
  getfa:=getfa(fa[x]);
  re[x]:=re[x] xor re[fa[x]];
  fa[x]:=getfa;
end;
//============================================================================
procedure march;
var i,fx,fy,x,y,z,tmp:longint;
    flag:boolean;
begin
  for i:=1 to n+m-2 do
  begin
    fa[i]:=i; co[i]:=-1; re[i]:=0;
  end; flag:=true;
  for i:=1 to k do
  begin
    if (l[i]=1) and (h[i]=1) then continue;
    if l[i]=1 then  //在第一列。
    begin
      z:=m-1+h[i]-1;
      fx:=getfa(z);
      if co[fx]=-1 then co[fx]:=c[i] xor re[z] else  //未被染色,修改颜色。
        if co[fx] xor re[z]<>c[i] then  //已染色,判断是否冲突。
        begin flag:=false; break; end;
      continue;
    end else
    if h[i]=1 then  //在第一行。
    begin
      z:=l[i]-1;
      fx:=getfa(z);
      if co[fx]=-1 then co[fx]:=c[i] xor re[z] else  //未被染色,修改颜色。
        if co[fx] xor re[z]<>c[i] then  已染色,判断是否冲突。
        begin flag:=false; break; end;
      continue;
    end;
    x:=m-1+h[i]-1; y:=l[i]-1;
    fx:=getfa(x);
    fy:=getfa(y);
    if (h[i] mod 2=0) and (l[i] mod 2=0) then
    begin
      if c[i]=1 then
      begin
        if (fx=fy) and (re[x] xor re[y]<>0) then
        begin flag:=false; break; end;
        re[fx]:=re[x] xor re[y];
        fa[fx]:=fy;
        if co[fx]>-1 then  //合并两个集合的时候也要将颜色带上。。
        begin
          if co[fy]=-1 then co[fy]:=co[fx] xor re[fx] else
          if co[fy]<>co[fx] xor re[fx] then
          begin flag:=false; break; end;
        end;
      end else
      begin
        if (fx=fy) and (re[x] xor re[y]<>1) then
        begin flag:=false; break; end;
        re[fx]:=re[x] xor re[y] xor 1;
        fa[fx]:=fy;
        if co[fx]>-1 then  //合并两个集合的时候也要将颜色带上。。
          if co[fy]=-1 then co[fy]:=co[fx] xor re[fx] else
          if co[fy]<>co[fx] xor re[fx] then
          begin flag:=false; break; end;
      end;
    end else
    begin
      if c[i]=1 then
      begin
        if (fx=fy) and (re[x] xor re[y]<>1) then
        begin flag:=false; break; end;
        re[fx]:=re[x] xor re[y] xor 1; fa[fx]:=fy;
        if co[fx]>-1 then
          if co[fy]=-1 then co[fy]:=co[fx] xor re[fx] else
          if co[fy]<>co[fx] xor re[fx] then
          begin flag:=false; break; end;
      end else
      begin
        if (fx=fy) and (re[x] xor re[y]<>0) then
        begin flag:=false; break; end;
        re[fx]:=re[x] xor re[y]; fa[fx]:=fy;
        if co[fx]>-1 then
          if co[fy]=-1 then co[fy]:=co[fx] xor re[fx] else
          if co[fy]<>co[fx] xor re[fx] then
          begin flag:=false; break; end;
      end         //话说这里粘贴了4个几乎一样的。。代码量暴涨。。。
    end;
  end;
  if not(flag) then exit;
  for i:=1 to n+m-2 do p[i]:=false;
  tmp:=1;
  for i:=1 to n+m-2 do
  begin
    fx:=getfa(i);
    if not(p[fx]) and (co[fx]=-1) then
    begin
      tmp:=(tmp*2) mod mo;
      p[fx]:=true;
    end;
  end;
  ans:=(ans+tmp) mod mo;
end;
//============================================================================
begin
  readln(n,m,k); flagg:=false;
  for i:=1 to k do
  begin
    readln(h[i],l[i],c[i]);
    if (l[i]=1) and (h[i]=1) then
    begin
      flagg:=true; tt:=c[i];
    end;
  end;
  if flagg and (tt=1) then
    for i:=1 to k do c[i]:=c[i] xor 1;
  march;
  if not(flagg) then
  begin
    for i:=1 to k do c[i]:=c[i] xor 1;
    march;
  end;
  writeln(ans);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值