Apio-11-Color

本文深入探讨了一道难题,通过巧妙利用并查集算法解决2*2矩阵xor运算为1的问题。首先,作者推导出关键公式,并通过实例验证其正确性。接着,介绍了如何通过并查集不断合并矩阵,最终计算出方案数量。文章以实际代码实现,详细解释了判断条件和逻辑流程,为读者提供了一个完整的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题憋了我好久,原来在网站上评测怎么也不过,今天重写了一遍,下了下官网上的数据来测,就这么过了~
这题主要就是每个2*2的矩阵的xor值都是1,经过推导可以得到:
    g[1,1] xor g[1,b] xor g[a,1] xor g[a,b]=((a mod 2=0)and(b mod 2=0)) xor g[a,b];
由于两个元素的xor值是可以传递的,然后就可以用并查集不断的合并,
最后方案数即为2^tot,(tot=连通分量的数量).
===================================================================

{
判断(1,1)是否已经确定,若已确定且(1,1)=1,则将所有点的颜色取反;

初始化每一个集合,集合数为tot=n+m-1;

对于任意的(a,b)=c,
 若(a=1)or(b=1)则(a,b)=c,
 否则,若((a mod 2=0)and(b mod 2=0))xor(c=1)则(1,b)xor(a,1)=1,
      否则(1,b)xor(a,1)=0;

每次合并两个集合时,tot=tot-1,若出现矛盾则输出0;

最后,答案为(2^tot)mod(1000000000);
}
const red=2000001;
      blue=2000002;
var p,d:array[1..2000002] of longint;
    a,b,c:array[1..1000000] of longint;
    n,m,k,tot,i,ps,co,ans:longint;
procedure f(x:longint;var fx,dx:longint);
begin
     if p[x]=0 then begin
        fx:=x;
        dx:=0;
     end else begin
        f(p[x],fx,dx);
        p[x]:=fx;
        d[x]:=dx xor d[x];
        dx:=d[x];
     end;
end;
procedure union(a,b,dis:longint);
var fa,da,fb,db:longint;
begin
     f(a,fa,da);
     f(b,fb,db);

     if (fa=fb)and(da xor db<>dis)then begin
        write(0); close(input); close(output); halt;
     end;

     if fa<>fb then begin
        p[fa]:=fb;
        d[fa]:=da xor db xor dis;
        dec(tot);
     end;
end;
begin
     assign(input,'color.in'); reset(input);
     assign(output,'color.out'); rewrite(output);
     readln(n,m,k);
     ps:=2;
     for i:=1 to k do begin
         readln(a[i],b[i],c[i]);
         if (a[i]=1)and(b[i]=1)then
            if (co<>2)and(co<>c[i])then begin
               write(0);close(input);close(output); halt;
            end else co:=c[i];
     end;
     if co=1 then
     for i:=1 to k do c[i]:=1-c[i];
     fillchar(p,sizeof(p),0);
     fillchar(d,sizeof(d),0);
     union(red,blue,1);
     tot:=n+m-1;
     for i:=1 to k do begin
         //if (a[i]=0)or(b[i]=0)then continue;
         if a[i]=1 then if c[i]=1 then union(red,b[i],0) else union(blue,b[i],0)
         else if b[i]=1 then if c[i]=1 then union(red,m+a[i],0) else union(blue,m+a[i],0)
         else if ((a[i]mod 2=0)and(b[i]mod 2=0))xor(c[i]=1) then union(b[i],m+a[i],1) else union(b[i],m+a[i],0);
     end;
     ans:=1;
     for i:=1 to tot do ans:=(ans*2)mod 1000000000;
     writeln(ans);
     close(input); close(output);
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值