码迷,mamicode.com
首页 > Windows程序 > 详细

【BZOJ2303】【Apio2011】方格染色 异或方程+并查集

时间:2015-04-17 11:41:50      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:bzoj2303   apio2011   方格染色   异或方程   并查集   

链接:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/45081583");
}

题解:

首先我们发现对于 ai,j 有下列式子:
ai,j xor ai+1,j xor ai,j+1 xor ai+1,j+1==1
然后推导得到对于 ai,j 有下列式子:
a1,1 xor a1,j xor ai,1 xor ai,j==!i,j

然后显然如果我们先涂上第一行和第一列,剩下的点的染色方案是唯一的。
而这些已经的填涂 (i,j) 则成了 (1,j)(i,1) 这俩点之间的限制,即方程四点异或和确定。

我们可以先枚举 (1,1)0 还是 1 ,然后其它的染色作为点之间关系跑并查集。
然后会剩下 x 个连通块,刨去 1 的一个,则此种对 1 染色的方案(染0或者染1)的答案贡献就是 2x?1

实现:

一些定义:
一个被提前染色了的点有染色权值为其染的色,而如果这个点横纵坐标皆为偶数,则权值取反。

首先说左上角为 0 时的答案计算:
对于点 (i,j),i>1j>1 则它是 点 i 和 点j+n 之间的限制,表示这两点之间差异为其染色权值。
【原因:如果权值为1,左上角还是0,那么俩点最终染色必须不一样对吧,反之亦然】
对于其它情况,即点在第一行或第一列上,我们认为这是在表示此点和点 (1,1) 的关系,处理方式可以与上一种情况相同(甚至在我的实现下代码也是相同哒,不用特殊考虑!)
【原因:如果权值为1,表示与 (0,0) 目前 0 的染色不同。】

然后对于左上角是 1 时的答案计算:
我们只需要把所有点的染色权值取反,然后推一下发现正好可以跟上述做相同处理。
也就是直接调用上述流程就可以啦!!

特殊问题:
如果点 (1,1) 被染色,那么需要特殊判定上面对 1 的枚举。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1001000
#define mod 1000000000
#define A e[i].x
#define B e[i].y+n
#define C e[i].z
using namespace std;
struct Eli
{
    int x,y,z;
    bool read()
    {
        scanf("%d%d%d",&x,&y,&z);
        if(x==1&&y==1)return 1;
        if(!((x|y)&1))z^=1;
        return 0;
    }
}e[N];
int f[N<<1];
bool g[N<<1];
int find(int x)
{
    if(f[x]==x)return x;
    find(f[x]);
    g[x]^=g[f[x]];
    return f[x]=f[f[x]];
}
long long power(long long x,long long p)
{
    long long ret=1;
    while(p)
    {
        if(p&1)ret=(ret*x)%mod;
        x=(x*x)%mod,p>>=1;
    }
    return ret;
}
int n,m,p;
long long getans()
{
    int i,fa,fb,t;
    for(i=1;i<=n+m;i++)f[i]=i,g[i]=0;
    f[n+1]=1;
    for(i=1;i<=p;i++)
    {
        fa=find(A),fb=find(B),t=g[A]^g[B]^C;
        if(fa!=fb)f[fb]=fa,g[fb]=t;
        else if(t)return 0;
    }
    long long ans=0;
    if(i>p)for(ans=0,i=1;i<=n+m;i++)
        if(find(i)==i)ans++;
    return power(2,ans-1);
}
bool f1=1,f2=1;
long long ans1,ans2;
int main()
{
    freopen("test.in","r",stdin);
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=p;i++)
    {
        if(e[i].read())
        {
            i--,p--;
            if(e[i].z)f1=0;
            else f2=0;
        }
    }

    if(f1)ans1=getans();
    if(f2)
    {
        for(int i=1;i<=p;i++)
            if(e[i].x>1&&e[i].y>1)e[i].z^=1;
        ans2=getans();
    }

    cout<<(ans1+ans2)%mod<<endl;
    return 0;
}

【BZOJ2303】【Apio2011】方格染色 异或方程+并查集

标签:bzoj2303   apio2011   方格染色   异或方程   并查集   

原文地址:http://blog.csdn.net/vmurder/article/details/45081583

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!