题目描述
Sam和他的妹妹Sara有一个包含n × m个方格的表格。她们想要将其的每个方格都染成红色或蓝色。出于个人喜好,他们想要表格中每个2 × 2的方形区域都包含奇数个(1 个或 3 个)红色方格。。
可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?
题解
如果我们令红色为1,蓝色为0,那么可以有每一个2x2的方格它们的异或都应该是1,然后多次异或,可以得到
当i,j中有一个是奇数时,有
x[i][j]=x[i][1]xor x[1][j]xor x[1][1]
x
[
i
]
[
j
]
=
x
[
i
]
[
1
]
x
o
r
x
[
1
]
[
j
]
x
o
r
x
[
1
]
[
1
]
当都是偶数时,有
x[i][j]=x[i][1]xor x[1][j]xor x[1][1]xor 1
x
[
i
]
[
j
]
=
x
[
i
]
[
1
]
x
o
r
x
[
1
]
[
j
]
x
o
r
x
[
1
]
[
1
]
x
o
r
1
因此,若第一行和第一列颜色确定了,那么就可以确定整个矩形
然后呢对于那些已知的点,我们可以看做是它的行和列之间的关系
用并查集来维护这些关系
答案就是
2k−1其中k为联通块个数
2
k
−
1
其
中
k
为
联
通
块
个
数
注意x[1][1]也是要枚举的,所以我们做两次
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=200005;
const int mod=1e9;
typedef long long ll;
int fa[N];
int g[N];
int n,m,k;
int x[N],y[N],c[N];
int find_father(int x){
if(x==fa[x]) return x;
int tmp=find_father(fa[x]);
g[x]^=g[fa[x]];
return fa[x]=tmp;
}
ll Pow2(int x){
ll res=1;
ll f=2;
while(x){
if(x&1)
res=(res*f)%mod;
f=(f*f)%mod;
x>>=1;
}
return res;
}
ll Solve(int color){
for(int i=1;i<=n+m;i++)
fa[i]=i,g[i]=0;
fa[n+1]=1;
for(int i=1;i<=k;i++){
int r,p1=x[i],p2=y[i]+n;
int f1=find_father(p1),f2=find_father(p2);
if(x[i]&1||y[i]&1)
r=color^c[i]^g[x[i]]^g[y[i]+n];
else
r=color^c[i]^g[x[i]]^g[y[i]+n]^1;
if(f1!=f2)
fa[f2]=f1,g[f2]=r;
else if(r)
return 0;
}
int cnt=0;
for(int i=1;i<=n+m;i++){
if(find_father(i)==i)
cnt++;
}
return Pow2(cnt-1);
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
int vis=-1;
for(int i=1;i<=k;i++){
scanf("%d%d%d",&x[i],&y[i],&c[i]);
if(x[i]==1&&y[i]==1)
vis=c[i];
}
ll ans=0;
if(vis==-1)
ans=(Solve(0)+Solve(1))%mod;
else
ans=Solve(vis);
printf("%lld\n",ans);
}