标签:bzoj2303 apio2011 方格染色 异或方程 并查集
#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/45081583");
}
首先我们发现对于
然后推导得到对于
然后显然如果我们先涂上第一行和第一列,剩下的点的染色方案是唯一的。
而这些已经的填涂
我们可以先枚举
然后会剩下
一些定义:
一个被提前染色了的点有染色权值为其染的色,而如果这个点横纵坐标皆为偶数,则权值取反。
首先说左上角为
对于点
【原因:如果权值为1,左上角还是0,那么俩点最终染色必须不一样对吧,反之亦然】
对于其它情况,即点在第一行或第一列上,我们认为这是在表示此点和点
【原因:如果权值为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