Luogu P3631 【[APIO2011]方格染色】

T15 Apio2011 方格染色

20分算法:暴力枚举每个点

抄题解做的还是好好写总结吧

把红色视为0,蓝色视为1

假设有一个表格如下:

A C E G
B D F H

根据题设有\(A\bigoplus B\bigoplus C\bigoplus D=C\bigoplus D\bigoplus E\bigoplus F=1\)

然后有\(A\bigoplus B\bigoplus E\bigoplus F=0\)

\(E\bigoplus F\bigoplus G\bigoplus H=1\)

所以\(A\bigoplus B\bigoplus G\bigoplus H=1\)

再放到一般性的表格中

A ...... C
B ...... D
I ...... J
....... ...... .......
E ...... G
F ...... H

当C,D处于奇数列的时候,有:

\(A\bigoplus B\bigoplus C\bigoplus D=0,E\bigoplus F\bigoplus G\bigoplus H=0,B\bigoplus I\bigoplus D\bigoplus J=0\)

所以有:

\(A\bigoplus C\bigoplus I\bigoplus J=0\)

推出

\(A\bigoplus C\bigoplus F\bigoplus H=0\)

即:

\(A\bigoplus H=C\bigoplus F\)

当C,D在偶数列上,有:

\(A\bigoplus B\bigoplus C\bigoplus D=1,E\bigoplus F\bigoplus G\bigoplus H=1,B\bigoplus I\bigoplus D\bigoplus J=1\)

当H在奇数行:

\(1\bigoplus A\bigoplus H=C\bigoplus F\)

当H在偶数行:

\(A\bigoplus H=C\bigoplus F\)

设H坐标为\((i,j)\),A坐标为\((1,1)\)

则有:
\(if(i\ mod\ 2==0\ and\ j\ mod \ 2==0) \ 1\bigoplus(1,1)\bigoplus(i,j) ==(1,j)\bigoplus(i,1)\)
\(else\ (1,1)\bigoplus(i,j) ==(1,j)\bigoplus(i,1)\)

而显然如果确定了第一排,第一列,那么可以确定整张图。

所以可以枚举\((1,1)\)的值,然后合并所有相关的集合,去掉已知点的集合,剩下的集合个数为\(cnt\),则答案为\(2^{cnt}\)
把(1,1)为0,1的答案加起来即可

合并集合的时候使用扩展域并查集维护到根节点的异或值。

#include <cstdio>
#include <cstring>
#include <cstdlib>

#define R register
#define ll long long

const int MAXN=1e6+10;
const int Mod=1e9;

inline int read()
{
	int x=0,f=1;
	char a=getchar();
	for(;a>'9'||a<'0';a=getchar()) if(a=='-') f=-1;
	for(;a>='0'&&a<='9';a=getchar()) x=x*10+a-'0';
	return x*f;
}

int n,m,k,flg=-1,cnt,Size;
int fa[MAXN];
int X[MAXN],Y[MAXN],Z[MAXN];

inline int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); }
inline void merge(int x,int y)
{	
	int fx=find(x),fy=find(y); 
	fa[fx]=fy;cnt-=fx!=fy;
}

inline void Init()
{
	n=read();m=read();k=read();
	Size=n+m-1;
	for(R int i=1;i<=k;i++)
	{
		X[i]=read();Y[i]=read();Z[i]=read();
		if(X[i]==1&&Y[i]==1) flg=Z[i];
	}
}

inline int id(int x) { return x==1?1:m+x-1; }

int vis[MAXN];
int ans=0;

inline void Solve(bool delta)
{
	for(R int i=1;i<=Size*2;i++) fa[i]=i;
	cnt=Size*2;
	for(R int i=1;i<=k;i++)
	{
		int a=X[i],b=Y[i];
		if(a==1&&b==1) continue;
		if(a%2==0&&b%2==0)
		{
			if(1^delta^Z[i]) 
			{
				merge(id(a),b+Size);merge(id(a)+Size,b);
			}
			else
			{
				merge(id(a),b);merge(id(a)+Size,b+Size);
			}
		}
		else
		{
			if(delta^Z[i]) 
			{
				merge(id(a),b+Size);
				merge(id(a)+Size,b);
			}
			else
			{
				merge(id(a),b);
				merge(id(a)+Size,b+Size);
			}
		}
		if(find(b)==find(b+Size)||find(id(a))==find(id(a)+Size))
		{
			printf("0\n");
			exit(0);
		}
	}
	memset(vis,0,sizeof(vis));
	cnt--;
	vis[find(1)]=1;
	for(R int i=1;i<=k;i++)
	{
		if(X[i]==1&&vis[find(Y[i])]==0) 
		{
			vis[find(Y[i])]=1;
			cnt--;
		}
		else 
			if(Y[i]==1&&vis[find(id(X[i]))]==0)
			{
				vis[find(id(X[i]))]=1;
				cnt--;
			}
	}
	cnt>>=1;
	int tmp=1;
	for(R int i=1;i<=cnt;i++) tmp=(tmp<<1)>=Mod?(tmp<<1)-Mod:(tmp<<1);
	ans=ans+tmp>=Mod?ans+tmp-Mod:ans+tmp;
}

int main()
{
	Init();
	if(flg==-1) Solve(0),Solve(1);
	if(flg==0) Solve(0);
	if(flg==1) Solve(1);
	printf("%d\n",ans);
	return 0;
}
posted @ 2020-04-30 17:37  HN-wrp  阅读(194)  评论(0编辑  收藏  举报