[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除所得到的余数)。
输入输出样例
说明
对于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 }