[BZOJ]2303: [Apio2011]方格染色 并查集
2017-10-10 16:59
253 查看
Description
Sam和他的妹妹Sara有一个包含n × m个方格的
表格。她们想要将其的每个方格都染成红色或蓝色。
出于个人喜好,他们想要表格中每个2 × 2的方形区
域都包含奇数个(1 个或 3 个)红色方格。例如,右
图是一个合法的表格染色方案(在打印稿中,深色代
表蓝色,浅色代表红色) 。
可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara
非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格
仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?
Sam和他的妹妹Sara有一个包含n × m个方格的
表格。她们想要将其的每个方格都染成红色或蓝色。
出于个人喜好,他们想要表格中每个2 × 2的方形区
域都包含奇数个(1 个或 3 个)红色方格。例如,右
图是一个合法的表格染色方案(在打印稿中,深色代
表蓝色,浅色代表红色) 。
可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara
非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格
仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?
题解:
好题啊!首先容易知道,如果确定了第一行和第一列的涂色方案,那么整个表格的涂色方案都是确定的,所以其实要求的就是第一行和第一列的染色方案数。然后对于一个格子(i,j),1为红色,0为蓝色,那么a[i][j] xor a[i][j+1] xor a[i+1][j] xor a[i+1][j+1]=1。设这个式子为S(i,j),那么我们把S(1,1)到S(i−1,j−1)异或起来,就得到a[1][1] xor a[1][j] xor a[i][1] xor a[i][j]=1(若i,j皆为偶数)或0(若i,j其中一个不是偶数),因为这相当于(i−1)∗(j−1)个1异或起来,所以只有当i,j皆为偶数时结果才为1。这样就有搞头了,因为我们已经知道了一部分的a[i][j],所以我们可以通过枚举a[1][1]是0或者1来对a[1][j]和a[i][1]进行限制。我们可以用一个带权的并查集来维护这些关系,因为我们知道了a[1][1]和a[i][j],所以我们就知道了a[1][j]和a[i][1]异或的结果,也就是它们是相同还是不同的,就可以用并查集维护了,g[x]表示x与他的父亲是否相同,相同为0,不同为1,也可以理解为差值,这样的话在一个连通块中的点,它们只要确定其中一个,其它的值全部都确定了,所以答案是2连通块数−1,因为有(1,1)这个点的连通块的值是确定的。矛盾或无解也可以维护。代码:
#include<bits/stdc++.h> using namespace std; #define LL long long const int Maxn=1000010; const int mod=1e9; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } int n,m,k,ans; struct A{int x,y,z;}a[Maxn]; int fa[Maxn],g[Maxn]; int findfa(int x) { if(fa[x]==x)return x; int t=findfa(fa[x]); g[x]^=g[fa[x]];return fa[x]=t; } int calc(int op) { int re=0; if(op==1) { for(int i=1;i<=k;i++) if(a[i].x!=1||a[i].y!=1)a[i].z^=1; } 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 fx=findfa(a[i].x),fy=findfa(a[i].y+n),temp; temp=g[a[i].x]^g[a[i].y+n]^a[i].z; if(fx!=fy){fa[fx]=fy;g[fx]=temp;} else if(temp)return re; } for(int i=1;i<=n+m;i++) if(findfa(i)==i)re=((!re)?1:re*2%mod); return re; } int main() { n=read();m=read();k=read(); int o=-1; for(int i=1;i<=k;i++) { a[i].x=read();a[i].y=read();a[i].z=read(); if(a[i].x==1&&a[i].y==1){o=a[i].z;k--;i--;continue;} if(a[i].x%2==0&&a[i].y%2==0)a[i].z^=1; } if(o==-1)ans=(calc(0)+calc(1))%mod; else ans=calc(o); printf("%d",ans); }
相关文章推荐
- BZOJ_2303_[Apio2011]方格染色 _并查集
- BZOJ 2303: [Apio2011]方格染色 并查集神题
- [BZOJ 2303][Apio2011]方格染色:并查集
- BZOJ 2303: [Apio2011]方格染色 [并查集 数学!]
- bzoj 2303: [Apio2011]方格染色【并查集】
- bzoj 2303: [Apio2011]方格染色 (并查集)
- 【bzoj 2303】【Apio2011】方格染色
- bzoj 2303 Apio2011 方格染色
- bzoj 2303: [Apio2011]方格染色
- BZOJ 2303: [Apio2011]方格染色 题解
- BZOJ 2303 [Apio2011]方格染色
- [BZOJ2303]-[Apio2011]方格染色-并查集+题目性质
- [BZOJ2303][APIO2011]方格染色 异或+并查集
- BZOJ2303 APIO2011方格染色(并查集)
- [杂题 异或 带权并查集] BZOJ2303: [Apio2011]方格染色
- [BZOJ2303][Apio2011]方格染色(数学相关+加权并查集)
- 2303: [Apio2011]方格染色
- 【BZOJ2303】【Apio2011】方格染色 异或方程+并查集
- BZOJ 2303 方格染色
- [Apio2011]方格染色