您的位置:首页 > 其它

[BZOJ]2303: [Apio2011]方格染色 并查集

2017-10-10 16:59 253 查看
Description

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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: