这题首先要推式子:
题目条件即为A(i-1,j-1) xor A(i-1,j) xor A(i,j-1) xor A(i,j)=1.
又有A(i-1,j-2) xor A(i-1,j-1) xor A(i,j-2) xor A(i,j-1)=1.
相邻两列两式异或得A(i-1,j-2)xor A(i,j-2) xor A(i-1,j) xor A(i,j)=0.
就这样一直递推过去,得A(i-1,1)xor A(i,1)xor A(i-1,j) xor A(i,j)=[j mod 2=0].
然后我们又有A(i-2,1) xor A(i-1,1) xor A(i-2,j) xor A(i-1,j)=[j mod 2=0].
就这样相邻两行不断异或,得A(1,1) xor A(i,1) xor A(1,j) xor A(i,j)=[(i mod 2=0)and(j mod 2=0)].
观察式子,我们发现如果A(1,1)确定,那么每一个已经涂好的颜色((x<>1)and(y<>1))都是对A(x,1)和A(1,y)的一个限制。于是我们枚举A(1,1)填0或1(当然如果A(1,1)事先被限制就只要一种)对第一行和第一列开并查集,用并查集维护限制。
!!!并查集维护异或限制!!!:若x xor y=0,就merge(x,y);merge(x’,y’)。若x xor y=1,就merge(x,y’);merge(x’,y)。
最后并查集会有很多联通块,记块数为sum。首先如果有x’和x在一个联通块中,则无解。接下来对于每一个第一行和第一列中已经被涂好的颜色,都使得一对连通块确定(即必须选其中一个而不能选另一个),我们记一个choose[root]=true,root为该连通块的编号,若choose[getfa(x)]和choose[getfa(x’)]同为true,则无解退出。否则sum=sum-2.
代码中是记得一个visit[].
最终答案为2^(sum/2),即每一对未确定的连通块都有两种选法。
最后把A(1,1)的两种情况的答案相加即可。
代码:
const
maxn=1000100;
md=1000000000;
type
node=record
x,y:longint;
c:-1..1;
end;
var
n,m,k,i,c1_1:longint;
ans:int64;
r:array[0..maxn]of node;
fa:array[0..4*maxn]of longint;
visit,chs:array[0..4*maxn]of boolean;
function getfa(v:longint):longint;
begin
if fa[v]=v then exit(v);
fa[v]:=getfa(fa[v]);
exit(fa[v]);
end;
procedure merge(x,y:longint);
begin
if getfa(x)<>getfa(y) then fa[getfa(x)]:=getfa(y);
end;
function ksm(a:int64;b:longint):int64;
begin
ksm:=1;
while b>0 do
begin
if b mod 2=1 then ksm:=ksm*a mod md;
a:=a*a mod md;
b:=b div 2;
end;
end;
procedure solve(flag:longint);
var
o,sum:longint;
begin
for i:=1 to 2*(n+m) do
fa[i]:=i;
for i:=1 to k do
with r[i] do
begin
if (x=1)or(y=1) then continue;
o:=c xor flag;
if (x mod 2=0)and(y mod 2=0) then o:=o xor 1;
if o=0 then begin merge(2*x,2*(n+y)); merge(2*x-1,2*(n+y)-1); end
else begin merge(2*x,2*(n+y)-1); merge(2*x-1,2*(n+y)); end;
end;
sum:=0;
for i:=1 to n+m do
begin
if getfa(2*i)=getfa(2*i-1) then exit;
visit[getfa(2*i)]:=true;
visit[getfa(2*i-1)]:=true;
end;
for i:=1 to 2*(n+m) do
if visit[i]=true then inc(sum);
sum:=sum div 2-2;
visit[1]:=false;
for i:=1 to k do
with r[i] do
begin
if (x=1)and(y<>1)and(visit[getfa(2*(n+y)-c)]=true) then
begin
visit[getfa(2*(n+y)-c)]:=false;
if visit[getfa(2*(n+y)-(c xor 1))]=false then exit;
dec(sum);
end;
if (x<>1)and(y=1)and(visit[getfa(2*x-c)]=true) then
begin
visit[getfa(2*x-c)]:=false;
if visit[getfa(2*x-(c xor 1))]=false then exit;
dec(sum);
end;
end;
ans:=(ans+ksm(2,sum))mod md;
end;
procedure work;
begin
fillchar(visit,sizeof(visit),false);
if c1_1<>1 then solve(0);
fillchar(visit,sizeof(visit),false);
if c1_1<>0 then solve(1);
end;
begin
readln(n,m,k);
c1_1:=-1;
for i:=1 to k do
begin
readln(r[i].x,r[i].y,r[i].c);
if (r[i].x=1)and(r[i].y=1) then c1_1:=r[i].c;
end;
work;
writeln(ans);
end.