bzoj 2303 Apio2011 方格染色

题目大意

有一个包含n × m的表格。
每个方格都染成红色或蓝色。
表格中每个2×2的方形区域都包含奇数个(1 个或 3 个)红色方格。
表格中的一些方格染上了颜色。
是否可能给剩下的方格染上颜色,使得整个表格仍然满足要求。
求染色方案数。

题解

我连判断都不会,还叫我求方案?
我还以为是差分约束系统,结果发现,一个点,与它相关的点不止一个,这就没法构图了是不是?
对于一个点
Ai,jxorAi1,jxorAi,j1xorAi1,j1=1
又有
Ai,jxorAi,j1xorAi+1,jxorAi+1,j1=1
等式两边一起异或一下。
Ai1,jxorAi1,j1xorAi+1,j1xorAi+1,j=0
按照这种方式类推,可以得到以下结论:
对于一个点,如果横坐标和纵坐标都是偶数,那么
Ai,jxorA1,1xorA1,jxorAi,1=1
否则
Ai,jxorA1,1xorA1,jxorAi,1=0
然后可以发现,如果第一行和第一列确定了,那么整张图就确定了。
这道题就变成了一道影子并查集的题。
先枚举 A1,1 的颜色,然后利用这些点之间的关系合并不同的点集。
最后统计有多少个可以自由选择的并查集。
这里有个地方需要注意:
如果这个点确定了,那么这个点的影子并查集也确定了,所以它的影子并查集就不可以再算一次了。
还有点 A1,1 已经被确定了。
答案就加上 2cnt

/**************************************************************
    Problem: 2303
    User: unicornt
    Language: C++
    Result: Accepted
    Time:408 ms
    Memory:49180 kb
****************************************************************/

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int M=1000005;
const int mod=1000000000;
int A[M],B[M],C[M];
int par[M<<2],mark[M<<2];
bool flag[M<<2];
int get(int x){
    if(par[x]!=x) par[x]=get(par[x]);
    return par[x];
}
int fast_pow(int x){
    int b=2,res=1;
    while(x){
        if(x&1) res=(long long)res*b%mod;
        b=(long long)b*b%mod;
        x>>=1;
    }
    return res;
}
int main(){
    int n,m,num;
    scanf("%d%d%d",&n,&m,&num);
    for(int i=0;i<num;i++)
        scanf("%d%d%d",&A[i],&B[i],&C[i]);
    int ans=0;
    for(int col=0;col<2;col++){//col(1,1)
        for(int i=1;i<=n+n+m+m;i++)
            par[i]=i;
        bool f=1;
        par[1]=n+n+1;
        par[1+n]=n+n+m+1;
        for(int i=0;i<num;i++){
            int Type=0;
            if(A[i]%2==0&&B[i]%2==0) Type=1;
            if(Type^col^C[i]){
                if(get(A[i])==get(B[i]+n+n)){
                    f=0;
                    break;
                }
                par[get(n+n+B[i]+m)]=get(A[i]);
                par[get(A[i]+n)]=get(n+n+B[i]);
            }else{
                if(get(A[i])==get(B[i]+n+n+m)){
                    f=0;
                    break;
                }
                par[get(A[i]+n)]=get(n+n+B[i]+m);
                par[get(A[i])]=get(n+n+B[i]);
            }
        }
        if(!f) continue;
        for(int i=1;i<=n+n+m+m;i++)
            flag[i]=0;
        int cnt=0;
        for(int i=1;i<=n;i++){
            if(!flag[get(i)]){
                flag[get(i)]=1;
                flag[get(i+n)]=1;
                cnt++;
            }
        }
        for(int i=1;i<=m;i++){
            if(!flag[get(n+n+i)]){
                flag[get(n+n+i)]=1;
                flag[get(n+n+i+m)]=1;
                cnt++;
            }
        }
        ans+=fast_pow(cnt-1);
        if(ans>=mod) ans-=mod;
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值