[杂题 异或 带权并查集] BZOJ2303: [Apio2011]方格染色

不太容易想到。首先要把限制看成异或,即每个点都要满足
ai,j xor ai,j1 xor ai1,j xor ai1,j1=1
这些限制太复杂了,怎么进行转化呢?
注意到,如果我们已经确定的第一行和第一列的所有元素,则其他也确定了。所以我们应该可以把限制都变成和第一行和第一列有关。
我们对于一个点 x,y 把所有在其左上范围的等式异或起来。得到:

a1,1 xor ax,1 xor a1,y xor ax,y=((x1)(y1)) and 1

可以想到,我们枚举 a1,1 的值,那么对于每个 ax,y=val 的限制,都可以转化为 ax,1 xor a1,y=c 。注意若 x=1 y=1 ,就还是看作单个元素的限制。
这样问题就变成,有一些01变量,给你一些两个数异或值的限制,和单个元素的值的限制,求合法方案数。
直接在有限制的点间连边,每个联通块的方案只可能是 0,1,2 ,最后相乘。
用带权并查集写起来会很方便。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=2000010,MOD=1e9;
typedef long long LL;
int n,m,K,a_11; 
struct data{ int x,y,val; } a[maxn];
int fa[maxn],xorfa[maxn],ans;
int getfa(int x){
    if(fa[x]==x) return x;
    int _fa=fa[x]; fa[x]=getfa(fa[x]);
    xorfa[x]^=xorfa[_fa]; return fa[x];
}
void Solve(){
    for(int i=1;i<=n+m-1;i++) fa[i]=i, xorfa[i]=0;
    for(int i=1;i<=K;i++){
        if(a[i].x==1&&a[i].y==1) continue;
        int x=a[i].x, y=(a[i].y==1?1:n+a[i].y-1), fax=getfa(x), fay=getfa(y), t=a_11^a[i].val^((a[i].x&1)==0&&(a[i].y&1)==0);
        //printf("%d ^ %d = %d\n",x,y,t);
        if(fax==fay){
            if((xorfa[x]^xorfa[y])!=t) return;
        } else fa[fax]=fay, xorfa[fax]=xorfa[x]^xorfa[y]^t;
    }
    LL res=1;
    for(int i=1;i<=n+m-1;i++) if(getfa(i)==i&&getfa(1)!=i) res=(res*2)%MOD;
    (ans+=res)%=MOD;
}
int main(){
    freopen("bzoj2303.in","r",stdin);
    freopen("bzoj2303.out","w",stdout);
    scanf("%d%d%d",&n,&m,&K);
    a_11=-1;
    for(int i=1;i<=K;i++){
        scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].val);
        if(a[i].x==1&&a[i].y==1){
            if(a_11!=-1&&a_11!=a[i].val) return printf("0"),0; 
            a_11=a[i].val;
        }
    }
    if(a_11!=-1) Solve(); else{
        a_11=0; Solve(); //printf("\n");
        a_11=1; Solve();
    }
    printf("%d\n",ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值