zoukankan      html  css  js  c++  java
  • 【题解】P3631 [APIO2011]方格染色

    题目链接

    题意

    有一个包含 (n imes m) 个方格的表格。要将其中的每个方格都染成红色或蓝色。表格中每个 (2 imes 2) 的方形区域都包含奇数个( (1) 个或 (3) 个)红色方格。例如,下面是一个合法的表格染色方案(R 代表红色,B 代表蓝色):

    B B R B R
    R B B B B
    R R B R B
    

    表格中的一些方格已经染上了颜色.求给剩下的表格染色,使得符合要求的方案数。

    思路

    每天一道压轴好题。 其实这题跟并查集没啥关系,只是用来维护而已

    题意可以简化为:在 (n imes m) 的矩阵中放 01,k 个格子已经放好了,要放满,且每个 (2 imes 2) 的格子中有奇数个1.

    由题意可知,任意四个格子(二乘二)的异或值为 1,不断异或相邻的两个“矩形”的异或式子 (如:(Aoplus Boplus Coplus D=Coplus Doplus Eoplus F=Eoplus Foplus Goplus H=1),选取相邻的式子得到 (Aoplus Boplus Eoplus F=0,Aoplus Boplus Goplus H=0) )

    由这个思路推广,设 (A(1,1),B(2,1),C(1,j),D(i,1))

    1. (C,D) 在奇数列上, (Aoplus Boplus Coplus D=0,Eoplus Foplus Goplus H=0,=> Aoplus Coplus Foplus H=0,Aoplus H=Coplus F.)
    2. (C,D) 在偶数列上。(Aoplus Boplus Coplus D=1,Eoplus Foplus Goplus H=1.) 此时,当 (H) 在偶数行,(1oplus Aoplus H=Coplus F) ;如果在奇数行,则有 (Aoplus H=Coplus F.)

    综上所述,对于任意 (H(i,j):)

    如果 (i|2,j|2) ,那么 (1oplus (1,1)oplus (i,j)=(1,j)oplus (i,1)) ;否则 ((1,1)oplus (i,j)=(1,j)oplus (i,1))

    这样就转化为对 ((1,j),(i,1)) 的约束。如果 ((1,1)) 没有给出,那么就要枚举两种情况。

    用并查集维护。(xoplus y=0) 时,合并 ((x,y),(x',y')) ;否则合并 ((x,y'),(x',y))。无解特判就是 (x,x'in S) (属于同一个集合)

    合并完成之后得到连通块个数 (sum) ,枚举所有已知点(注意 ((1,1)) 不算),去掉他们的连通块,剩下的就是未知个数,(2^{sum'}) 即为方案。把 ((1,1)) 的两种情况相加即可。

    注意:此题由于有虚点( (x',y') ),所以空间要两倍。

    代码

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int mod=1e9,N=2e5+10;
    int n,m,k,x[N],y[N],z[N],fa[N],g[N];
    
    ll power( ll a,ll b )
    {
            ll res=1;
            for ( ; b; b>>=1,a=a*a%mod )
                    if ( b&1 ) res=res*a%mod;
            return res;
    }
    
    int find( int x )
    {
            if ( x==fa[x] ) return x;
            int fat=find( fa[x] ); g[x]^=g[fa[x]]; 
            return fa[x]=fat;
    }
    
    int calc( int opt )
    {
            for ( int i=1; i<=n+m; i++ )
                    fa[i]=i,g[i]=0;
            fa[n+1]=1;
            if ( opt==1 )
                    for ( int i=1; i<=k; i++ )
                            if ( x[i]>1 && y[i]>1 ) z[i]^=1;
            for ( int i=1; i<=k; i++ )
            {
                    int x=:: x[i],y=:: y[i],z=:: z[i];
                    if ( x!=1 || y!=1 )
                    {
                            int fx=find(x),fy=find(y+n),ty=g[x]^g[n+y]^z;
                            if ( fx!=fy ) fa[fy]=fx,g[fy]=ty;
                            else if ( ty ) return 0;
                    }
            }
            int res=0;
            for ( int i=1; i<=n+m; i++ )
                    if ( i==find(i) ) res++;
            return power( 2,res-1 );
    }
    
    int main()
    {
            scanf( "%d%d%d",&n,&m,&k );
            int flag=-1;
            for ( int i=1; i<=k; i++ )
            {
                    scanf( "%d%d%d",&x[i],&y[i],&z[i] );
                    if ( (!(x[i]&1)) && (!(y[i]&1)) ) z[i]^=1;
                    if ( x[i]==1 && y[i]==1 ) flag=z[i];
            }
    
            if ( flag!=-1 ) printf( "%d
    ",calc( flag ) );
            else printf( "%d
    ",(calc(0)+calc(1))%mod );       
    }
    
  • 相关阅读:
    mongodb的常用操作(二)
    mongodb的常用操作
    OpenBSD内核之引导PBR
    OpenBSD内核之引导MBR
    OpenBSD之开篇
    “索引”、大数据的思考
    flume坑之channel.transactionCapacity和HdfsSink.batchSize
    cocos2d-x的CCAffineTransform相关变换实现原理
    MySQL JDBC/MyBatis Stream方式读取SELECT超大结果集
    “全服单世界”的终极目标即“虚拟世界”
  • 原文地址:https://www.cnblogs.com/UntitledCpp/p/13913843.html
Copyright © 2011-2022 走看看