[Apio2011]方格染色
2015-05-03 14:00
274 查看
题意:
有一个n*m的矩阵,可以放入0或1,现在已经有k个格子放好了0或1,要把矩阵放满,要求是矩阵中每个2*2的格子有奇数个1。输入n、m和已经放了的格子,求方案数。题解:
首先要介绍位运算中的异或(^)的一个性质:a^b^a=b;把格子中的点的关系用异或运算来关联。观察下面的表格:
由题意可知,任意四个格子的异或值为1,即
A^B^C^D=C^D^E^F=E^F^G^H=…=1;
选取相邻的两式异或,得
A^B^E^F=0;
A^B^G^H=0;
由此推广,设A(1,1), B(2,1), C(1,j), D(i,1);
C、D在奇数列上,则 A^B^C^D=0; E^F^G^H=0; 由上下相邻两行不断异或得到: A^C^F^H=0;
即A^H=C^F;
C、D在偶数列上,则 A^B^C^D=1; E^F^G^H=1; 这回不太一样,因为1^1=0, 0^1=1,继续分类讨论:
①当H在偶数行时 A^C^F^H=1; 即1^A^H=C^F;
②当H在奇数行时 A^C^F^H=0; 即A^H=C^F;
综上,对于任意的H(i,j):
if(i%2==0 && j%2==0) 1^(1,1)^(i,j)==(1,j)^(i,1);
else (1,1)^(i,j)==(1,j)^(i,1);
这样就把题目条件转化成了对(1,j)和(i,1)的约束,而(1,1)如果未给出,是需要枚举两种情况的。这样的约束让人想到用并查集来操作,即x^y==0时Union(x,y)、Union(x’,y’);x^y==1时Union(x,y’)、Union(x’,y);其中,x’、y’是x、y的虚点。
注意判断无解情况:x与x’属于同一集合。
经过以上的合并,最后会得到连通块的个数sum(包括虚点),这时再枚举所有的已知点,把他们所在的连通块去除(注意要把(1,1)算入已知因为是枚举的)。剩下的sum’就是未知的连通块个数,2^sum即方案数。再把(1,1)分别填入0和1的方案数相加就得到最后结果。
总结:
这道题与其说是并查集不如说是异或方程…涨姿势了。
[code]#include <cstdio> #include <iostream> #include <cstdlib> #include <cstring> using namespace std; #define pos1(i) (i==1?1:m+i-1) const long mod=(long)1e9; const long maxn=(long)1e6+10; bool p[maxn*4]; int flag=-1; long n,m,M,K,ans,sum; long f[maxn*4]; struct point {long x,y;bool d;} a[maxn]; void read() { cin>>n>>m>>K; M=n+m-1; for(long i=1;i<=K;i++) { cin>>a[i].x>>a[i].y>>a[i].d; if(a[i].x==1 && a[i].y==1) flag=a[i].d; } } long find(long x) { if(f[x]!=x) return f[x]=find(f[x]); return f[x]; } void Union(long x,long y) { long h1=find(x),h2=find(y); if(h1!=h2) f[h1]=h2,sum--; } long long powermod(long k) { if(k==0) return 1; long long t=powermod(k/2); t=t*t; if(k%2==1) t=t*2%mod; return t%mod; } void dye(bool x) { for(long i=1;i<=2*M;i++) f[i]=i; sum=2*M; for(long k=1;k<=K;k++) { long i=a[k].x,j=a[k].y; if(i==1 && j==1) continue; if(!(i%2) && !(j%2)) { if(1^x^a[k].d) {Union(pos1(i),j+M);Union(pos1(i)+M,j);} else {Union(pos1(i),j);Union(pos1(i)+M,j+M);} } else { if(x^a[k].d) {Union(pos1(i),j+M); Union(pos1(i)+M,j);} else {Union(pos1(i),j);Union(pos1(i)+M,j+M);} } if(find(j)==find(j+M) || find(pos1(i))==find(pos1(i)+M)) {cout<<"0";exit(0);} } memset(p,0,sizeof(p)); sum--;p[find(1)]=1; for(int i=1;i<=K;i++) if(a[i].x==1 && !p[find(a[i].y)]) p[find(a[i].y)]=1,sum--; else if(a[i].y==1 && !p[find(pos1(a[i].x))]) p[find(pos1(a[i].x))]=1,sum--; sum/=2; ans+=powermod(sum); } void work() { if(flag!=1) dye(0); if(flag!=0) dye(1); cout<<ans%mod; } int main() { ios::sync_with_stdio(false); read(); work(); return 0; }
Arya
2015-5-2
相关文章推荐
- [BZOJ2303]-[Apio2011]方格染色-并查集+题目性质
- BZOJ2303 APIO2011方格染色
- BZOJ2303: [Apio2011]方格染色
- BZOJ 2303: [Apio2011]方格染色 [并查集 数学!]
- BZOJ2303 APIO2011方格染色(并查集)
- [BZOJ 2303][Apio2011]方格染色:并查集
- [BZOJ2303][Apio2011]方格染色(数学相关+加权并查集)
- bzoj 2303: [Apio2011]方格染色 (并查集)
- BZOJ2303: [Apio2011]方格染色
- [APIO2011]方格染色
- [BZOJ2303][APIO2011]方格染色 异或+并查集
- BZOJ2303: [Apio2011]方格染色
- bzoj 2303: [Apio2011]方格染色【并查集】
- BZOJ 2303 [Apio2011]方格染色
- [Apio2011]方格染色
- BZOJ_2303_[Apio2011]方格染色 _并查集
- [BZOJ]2303: [Apio2011]方格染色 并查集
- bzoj 2303 Apio2011 方格染色
- 2303: [Apio2011]方格染色
- bzoj 2303: [Apio2011]方格染色