根据题目的条件可以列出方程为a[i][j]^a[i][j+1]^a[i+1][j]^a[i+1][j+1]=1,其中a[i][j]为1表示第(i,j)格染成红色。令这个式子为S(i,j),那么对于某一格(i,j),我们把S(1,1)...S(i-1,j-1)(也就是(i,j)左上的部分)异或以来,得到:
a[1][1]^a[i][1]^a[1][j]^a[i][j]=1(i,j都为偶数)或0(其他情况)
可以看到,只要确定了第一行和第一列就得到了所有的格子的情况(这是废话,n^2个变量(n-1)^2个方程自由变量当然有2n-1个了>_<,只不过取第一行和第一列的比较方便而已^_^)
另外,既然我们能弄出这个方程,那么显然有解辣。。(当然又让a[i][j]=0又让a[i][j]=1的条件除外)
然后题目中给出了部分a[i][j]的值,然么我们可以得到a[1][1]^a[i][1]^a[1][j]=a[i][j]^1,如果已经提前得到了a[1][1],那么就可以得到a[i][1]和a[1][j]的值,然后我们可以把a[i][1]和a[1][j]并到一个并查集里面(当然要先判断是否矛盾)。
那么最后有几个连通块最后答案就是2^(连通块的个数-1),因为和a[1][1]相连的那个连通块只有一种选法。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 1000000000
#define N 2000005
using namespace std;
struct node{ int x,y,z; }a[N]; int n,m,cnt,fa[N],g[N];
int read(){
int x=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x;
}
int getfa(int x){
if (x==fa[x]) return x; int t=getfa(fa[x]);
g[x]^=g[fa[x]]; return fa[x]=t;
}
int calc(){
int i,u,v,tmp;
for (i=1; i<=m+n; i++){ fa[i]=i; g[i]=0; }
fa[m+1]=1;
for (i=1; i<=cnt; i++){
u=getfa(a[i].x); v=getfa(a[i].y+m);
tmp=g[a[i].x]^g[a[i].y+m]^a[i].z;
if (u!=v){ fa[u]=v; g[u]=tmp; }
else if (tmp) return 0;
}
int ans=-1;
for (i=1; i<=m+n; i++)
if (getfa(i)==i)
if (ans==-1) ans=1; else{
ans<<=1; if (ans>=mod) ans-=mod;
}
return ans;
}
int main(){
m=read(); n=read(); cnt=read(); int i; bool bo[2]; bo[0]=bo[1]=1;
for (i=1; i<=cnt; i++){
a[i].x=read(); a[i].y=read(); a[i].z=read();
if (a[i].x+a[i].y==2){ bo[a[i].z]=0; i--; cnt--; continue; }
if (!((a[i].x|a[i].y)&1)) a[i].z^=1;
}
int ans=0; if (bo[1]) ans=calc();
if (bo[0]){
for (i=1; i<=cnt; i++)
if (a[i].x>1 && a[i].y>1) a[i].z^=1;
ans+=calc();
}
if (ans>=mod) ans-=mod; printf("%d\n",ans);
return 0;
}
by lych
2016.3.18