[APIO2011]方格染色

题目描述

Sam和他的妹妹Sara有一个包含n*m个方格的表格。他们想要将其中的每个方格都染成红色或蓝色。出于个人喜好,他们想要表格中每个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,分别代表表格的行数,列数和已被染色的方格数目。

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
3 4 3
2 2 1
1 2 0
2 3 1
输出样例#1: 复制
8

说明

对于20%的测试数据,n,m<=5,k<=5。

对于50%的测试数据,n,m<=5000,k<=25。

对于100%的测试数据,2<=n,m<=10^5,0<=k<=10^5,1<=x[i]<=n,1<=y[i]<=m。

首先发现,如果我们把蓝色看作1,把红色看作0,那么对于每一个格子a(i,j),都有:a(i,j)^a(i+1,j)^a(i,j+1)^a(i+1,j+1)=1

那么只要第一列和第一行确定了如何染色,整个表格的染色就确定了

如果(x,y)的值为1/0那么第一行和第一列的值就会有限制

如果(x,y)都是偶数,那么2*2的矩形总数为奇数,异或和为1

而且除了(1,1),(x,1),(1,y),(x,y)以外其它格子都异或了2次

所以a(1,1)^a(x,1)^a(1,y)^a(x,y)=1

即a(1,1)^a(x,1)^a(1,y)=a(x,y)^1

否则就是a(1,1)^a(x,1)^a(1,y)=a(x,y)

所以讨论a(1,1)的值可以得到a(x,1)和a(1,y)的值的异或关系

也就是说,存在下列关系

相同,不同,关系不确定,前两种都是连通,只不过关系不同

所以用带权并查集维护

d[x]表示x与他的根是相同还是不同

特别注意当确定了第一行/列的值时

那么该联通块的值就确定了

pd[x]表示x的值,不确定为-1

如果中间冲突返回0

最后结果是2^不确定值的联通块数

a(1,1)=1的情况吧所有a(x,y)^1就行了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 typedef long long lol;
 8 int set[200001],d[200001],pd[200001],n,m,k,x[200001],y[200001],w[200001],Mod=1e9;
 9 int find(int x)
10 {
11   if (set[x]==x) return x;
12   int t=set[x];
13   set[x]=find(set[x]);
14   d[x]=(d[x]+d[t])%2;
15   return set[x];
16 }
17 int work0()
18 {int i;
19   lol ans;
20   int p,q,t;
21   for (i=1;i<=n+m;i++)
22     set[i]=i,d[i]=0,pd[i]=-1;
23   pd[1]=0;
24   set[n+1]=1;
25   for (i=1;i<=k;i++)
26     {
27       if (x[i]==1&&y[i]==1) continue;
28       if (x[i]==1||y[i]==1)
29     {
30       if (y[i]==1) p=find(x[i]),t=x[i];
31       else p=find(y[i]+n),t=y[i]+n;
32       if (pd[p]==-1) pd[p]=d[t]^w[i];
33       else if (pd[p]!=(d[t]^w[i])) return 0;
34       continue;
35     }
36       int p=find(x[i]),q=find(y[i]+n);
37       if (p!=q)
38     {
39       set[p]=q;
40       d[p]=d[y[i]+n]^d[x[i]]^w[i];
41       if (pd[p]!=-1&&pd[q]!=-1&&(pd[p]^d[p])!=pd[q]) return 0;
42       if (pd[p]!=-1&&pd[q]==-1)
43         pd[q]=d[p]^pd[p],pd[p]=-1;
44     }
45       else
46     {
47       if ((d[x[i]]^d[y[i]+n]^w[i])==1) return 0;
48     }
49     }
50   ans=1;
51   for (i=1;i<=n+m;i++)
52     if (find(i)==i&&pd[i]==-1) ans=ans*2%Mod;
53   return ans;
54 }
55 int main()
56 {lol ans=0;
57   int i,flag=-1;
58   cin>>n>>m>>k;
59   for (i=1;i<=k;i++)
60     {
61       scanf("%d%d%d",&x[i],&y[i],&w[i]);
62       if (x[i]==1&&y[i]==1) flag=w[i];
63       if (!(x[i]&1)&&!(y[i]&1)) w[i]^=1;
64     }
65   if (flag==-1||flag==0) ans+=work0();
66   if (flag==-1||flag==1)
67     {
68       for (i=1;i<=k;i++)
69     w[i]^=1;
70       ans+=work0();
71       ans%=Mod;
72     }
73   cout<<ans;
74 }

 

posted @ 2018-04-22 19:49  Z-Y-Y-S  阅读(925)  评论(0编辑  收藏  举报