您的位置:首页 > 其它

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