bzoj 2303 方格染色

题目描述

Sam和他的妹妹Sara有一个包含n × m个方格的表格。她们想要将其的每个方格都染成红色或蓝色。出于个人喜好,他们想要表格中每个2 × 2的方形区域都包含奇数个(1 个或 3 个)红色方格。。
可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?

题解

如果我们令红色为1,蓝色为0,那么可以有每一个2x2的方格它们的异或都应该是1,然后多次异或,可以得到
当i,j中有一个是奇数时,有
x[i][j]=x[i][1]xor x[1][j]xor x[1][1] x [ i ] [ j ] = x [ i ] [ 1 ] x o r   x [ 1 ] [ j ] x o r   x [ 1 ] [ 1 ]
当都是偶数时,有
x[i][j]=x[i][1]xor x[1][j]xor x[1][1]xor 1 x [ i ] [ j ] = x [ i ] [ 1 ] x o r   x [ 1 ] [ j ] x o r   x [ 1 ] [ 1 ] x o r   1
因此,若第一行和第一列颜色确定了,那么就可以确定整个矩形
然后呢对于那些已知的点,我们可以看做是它的行和列之间的关系
用并查集来维护这些关系
答案就是 2k1k 2 k − 1 其 中 k 为 联 通 块 个 数
注意x[1][1]也是要枚举的,所以我们做两次

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=200005;
const int mod=1e9;
typedef long long ll;
int fa[N];
int g[N];
int n,m,k;
int x[N],y[N],c[N];
int find_father(int x){
    if(x==fa[x]) return x;
    int tmp=find_father(fa[x]);
    g[x]^=g[fa[x]];
    return fa[x]=tmp;
}
ll Pow2(int x){
    ll res=1;
    ll f=2;
    while(x){
        if(x&1)
            res=(res*f)%mod;
        f=(f*f)%mod;
        x>>=1;
    }
    return res;
}
ll Solve(int color){
    for(int i=1;i<=n+m;i++)
        fa[i]=i,g[i]=0;
    fa[n+1]=1;
    for(int i=1;i<=k;i++){
        int r,p1=x[i],p2=y[i]+n;
        int f1=find_father(p1),f2=find_father(p2);
        if(x[i]&1||y[i]&1)
            r=color^c[i]^g[x[i]]^g[y[i]+n];
        else
            r=color^c[i]^g[x[i]]^g[y[i]+n]^1;
        if(f1!=f2)
            fa[f2]=f1,g[f2]=r;
        else if(r)
            return 0;
    }
    int cnt=0;
    for(int i=1;i<=n+m;i++){
        if(find_father(i)==i)
            cnt++;
    }
    return Pow2(cnt-1);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    int vis=-1;
    for(int i=1;i<=k;i++){
        scanf("%d%d%d",&x[i],&y[i],&c[i]);
        if(x[i]==1&&y[i]==1)
            vis=c[i];
    }
    ll ans=0;
    if(vis==-1)
        ans=(Solve(0)+Solve(1))%mod;
    else
        ans=Solve(vis);
    printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值