BZOJ 2303: [Apio2011]方格染色 题解

题目大意:

  有n*m的方格,中间的数要么是1,要么是0,要求任意2*2的方格中的数异或和为1。已知一部分格子中的数,求合法的填数的方案数。

思路:

  由题意得:a[i][j]^a[i][j+1]^a[i+1][j]^a[i+1][j+1]=1,令这个式子为S(i,j),那么对于某一格(i,j),我们把S(1,1)...S(i,j)异或起来,则可得当i,j均为偶数时a[1][1]^a[i][1]^a[1][j]^a[i][j]=1(于是为了方便先预处理一下),否则a[1][1]^a[i][1]^a[1][j]^a[i][j]=0。可以枚举a[1][1]的值再由a[i][j]得到a[i][1]与a[1][j]的相同情况(可默认所有数均为0),于是相同就用并查集并起来。若有(n+1)个联通块则有$2^n$种方案(因为与a[1][1]相同的已经确定了)。

代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 const int M=2000009,mo=1000000000;
 5 int n,m,i,k,sum,u,v,t,ans,x[M],y[M],z[M],g[M],fa[M];
 6  
 7 int read()
 8 {
 9     int x=0;
10     char ch=getchar();
11     while (ch<'0' || ch>'9') ch=getchar();
12     while (ch>='0' && ch<='9') x=(x<<1)+(x<<3)+ch-48,ch=getchar();
13     return x;
14 }
15  
16 int getfa(int x)
17 {
18     if (x==fa[x]) return x;
19     int t=getfa(fa[x]);    g[x]^=g[fa[x]];
20     return fa[x]=t;
21 }
22  
23 int wk()
24 {
25     for (i=1;i<=n+m;i++) fa[i]=i,g[i]=0;
26     for (fa[n+1]=i=1;i<=k;i++)
27     {
28         u=getfa(x[i]),v=getfa(y[i]+n),t=g[x[i]]^g[y[i]+n]^z[i];
29         if (u!=v) fa[u]=v,g[u]=t;
30         else if (t) return 0;
31     }
32     for (sum=-1,i=1;i<=n+m;i++)
33         if (getfa(i)==i)
34             if (sum==-1) sum=1;
35             else if ((sum<<=1)>=mo) sum-=mo;
36     return sum;
37 }
38  
39 int main()
40 {
41     bool flag[2]={1,1};
42     n=read(),m=read(),k=read();
43     for (i=1;i<=k;i++)
44     {
45         x[i]=read(),y[i]=read(),z[i]=read();
46         if (x[i]+y[i]==2) { flag[z[i]]=0,i--,k--; continue; }
47         if (!((x[i]|y[i])&1)) z[i]^=1;
48     }
49     if (flag[1]) ans=wk();
50     if (flag[0])
51     {
52         for (i=1;i<=k;i++)
53             if (x[i]>1 && y[i]>1) z[i]^=1;
54         if ((ans+=wk())>=mo) ans-=mo;
55     }
56     printf("%d\n",ans);
57     return 0;
58 }

 

转载于:https://www.cnblogs.com/HHshy/p/5840018.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值