bzoj 2303: [Apio2011]方格染色 (并查集)
2017-04-28 20:13
459 查看
题目描述
传送门
题目大意:将每个方格都染成红色或蓝色。要表格中每个2 × 2的方形区域都包含奇数个(1 个或 3 个)红色方格。有些格子的颜色已经染好了,求给剩下的方格染上颜色,使得整个表格仍然满足要求的染色方案数题解
对于每个一个2*2的表格,我们可以把条件表示成异或方程的形式。对于每个位置(i,j),若填红色那么a[i][j]=1
S(i,j)=a[i][j]^a[i−1][j−1]^ a[i−1][j]^a[i][j−1]=1
然后对于每个位置维护S(i,j)的前缀和,那么a[1][1]^a[1][j]^a[i][1]^a[i][j]=!(i,j都是偶数)
可以发现只有i,j都是偶数的时候,前缀中才有奇数个方程,而且只有a[1][1],a[1][j],a[i][1],a[i][j]出现了奇数次。
然后可以发现染色的方案其实只与第一行第一列的点有关系。
那么如果枚举(1,1)的取值,那么对于所有给出的(i,j),我们将式子变成a[1][j]^a[i][1]=!(i,j都是偶数)^a[i][j]^a[1][1]。如果右边的值为1,那么说明a[1][j],a[i][1]的取值相同,否则不同。那么如果我们用并查集将所有的关系连接的话,在一个连通块中的取值只要其中一个确定了剩余的取值都是唯一的。
那么答案其实就是2^(连通块个数-1),为什么要-1?因为(1,1)的值我们已经枚举过了,所以取值是位置确定的。
那么我们考虑如何用并查集连接,因为既有不等关系又有相等关系,所以我们可以维护加权并查集,g[i]表示i到代表元素是相等还是不相等,1表示不相等。那么每次合并的时候只有异或一下就好了,两个不等号不就又变成相等了嘛。另外我们在合并的时候还可以判断一下无解,如果两个东西在一个集合中我们可以得到他们之间的关系(相等或者不相等),如果和当前要连接的关系冲突,那么无解。
还有就是本身在第一行或者第一列中的点。我们可以直接将他们连到(1,1)上去,反正值已经确定了,如果取值相同g[i]=0,否则g[i]=1.
还要特判一下(1,1)是否被限制了,计算的时候需要特判。
对于一个点在第一行或者第一列,如果被限制了两次,且两次的值不同,那么需要特判掉无解的情况。
代码
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define N 2000003 #define LL long long #define p 1000000000 using namespace std; struct data{ int x,y,opt,v; }a ; int fa ,F ,n,m,k,mark ,col ,g ; int find(int x) { if (fa[x]==x) return x; int t=find(fa[x]); g[x]^=g[fa[x]]; fa[x]=t; return fa[x]; } LL quickpow(int num,int x) { LL base=num; LL ans=1; while (x){ if (x&1) ans=ans*base%p; x>>=1; base=base*base%p; } return ans; } int cmp(data a,data b) { return a.opt<b.opt||a.opt==b.opt&&a.v<b.v; } LL solve() { for (int i=1;i<=n+m;i++) fa[i]=i,g[i]=0; fa[n+1]=1; for (int i=1;i<=n+m;i++) if (mark[i]) { fa[i]=1; if (col[1]==col[i]) g[i]=0; else g[i]=1; } sort(a+1,a+k+1,cmp);int K=0; for (int i=k;i>=1;i--) if (!a[i].opt) { K=i; break; } for (int i=1;i<=K;i++) { int r1=find(a[i].x); int r2=find(a[i].y+n); int t=g[a[i].x]^g[a[i].y+n]^a[i].v; if (r1!=r2) fa[r2]=r1,g[r2]=t; else if (t) return 0; } int ans=0; for (int i=1;i<=n+m;i++) if (find(i)==i&&!mark[i]) ans++; //cout<<ans<<endl; return quickpow(2,max(0,ans-1)); } int main() { freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d%d%d",&n,&m,&k); bool p0,p1; p0=p1=true; for (int i=1;i<=k;i++) { scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].v); if (a[i].x==1&&a[i].y==1) { if (a[i].v) p0=false; else p1=false; a[i].opt=1; } else{ if (!(a[i].x&1)&&!(a[i].y&1)) a[i].v^=1; if (a[i].x==1) { if (!mark[a[i].y+n])mark[a[i].y+n]=1,col[a[i].y+n]=a[i].v,a[i].opt=1; else { if (col[a[i].y+n]!=a[i].v) { printf("0\n"); return 0; }else a[i].opt=1; } } if (a[i].y==1){ if (!mark[a[i].x]) mark[a[i].x]=1,col[a[i].x]=a[i].v,a[i].opt=1; else{ if (col[a[i].x]!=a[i].v) { printf("0\n"); return 0; }else a[i].opt=1; } } } } LL ans0=0,ans1=0; if (p0) col[1]=0,ans0=solve(); if (p1) { col[1]=1; for (int i=1;i<=k;i++) a[i].v^=1; ans1=solve(); } printf("%lld\n",(ans0+ans1)%p); }
相关文章推荐
- 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】方格染色
- 2303: [Apio2011]方格染色
- 【BZOJ2303】【Apio2011】方格染色 异或方程+并查集
- [BZOJ2303][APIO2011]方格染色 异或+并查集
- [BZOJ2303]-[Apio2011]方格染色-并查集+题目性质
- BZOJ2303 APIO2011方格染色(并查集)
- [BZOJ2303][Apio2011]方格染色(数学相关+加权并查集)
- [杂题 异或 带权并查集] BZOJ2303: [Apio2011]方格染色
- BZOJ2303: [Apio2011]方格染色
- BZOJ2303: [Apio2011]方格染色