BZOJ2303: [Apio2011]方格染色

Description

Sam和他的妹妹Sara有一个包含n × m个方格的
表格。她们想要将其的每个方格都染成红色或蓝色。
出于个人喜好,他们想要表格中每个2 ×   2的方形区
域都包含奇数个(1 个或 3 个)红色方格。例如,右
图是一个合法的表格染色方案(在打印稿中,深色代
表蓝色,浅色代表红色) 。 
可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara
非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格
仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢? 


Input

输入的第一行包含三个整数n, m和k,分别代表表格的行数、列数和已被染
色的方格数目。 
之后的k行描述已被染色的方格。其中第 i行包含三个整数xi, yi和ci,分别
代表第 i 个已被染色的方格的行编号、列编号和颜色。ci为 1 表示方格被染成红
色,ci为 0表示方格被染成蓝色。 

Output

输出一个整数,表示可能的染色方案数目 W 模 10^9得到的值。(也就是说,如果 W大于等于10^9,则输出 W被10^9除所得的余数)。 

对于所有的测试数据,2 ≤ n, m ≤ 106
,0 ≤ k ≤ 10^6
,1 ≤ xi ≤ n,1 ≤ yi ≤ m。 

Sample Input

3 4 3
2 2 1
1 2 0
2 3 1

Sample Output

8

HINT

数据为国内数据+国际数据+修正版


鸣谢GYZ

Source

并查集
考虑第一行和第一列 如果已经确定 则所有的都可以确定
(i,j)上的数为xi^yj^(1,1)^(i,j都是偶数)
然后枚举(1,1) 注意特判
用带权并查集判能否可行 最后答案就是2^(联通块个数-1) 因为枚举了1,1这个点
注意是g[x]^=g[f[x]]而不是g[x]^=g[fx]
#include<bits/stdc++.h>

using namespace std;

const int maxn=1000010;
const int mod=1e9;

int f[maxn<<1],g[maxn<<1],n,m,k;

struct node
{
	int x,y,w;
}e[maxn];

int findfa(int x)
{
	if(f[x]==x) return x;
	int fx=findfa(f[x]);
	g[x]^=g[f[x]];
	return f[x]=fx;
}

inline int poww(int x,int y)
{
	int tmp=x,s=1;
	while(y)
	{
		if(y&1)
			s=1ll*s*tmp%mod;
		tmp=1ll*tmp*tmp%mod;
		y>>=1;
	}
	return s;
}

inline int cal()
{
	int N=n+m;
	for(int i=1;i<=N;i++) f[i]=i,g[i]=0;
	f[n+1]=1;
	for(int i=1;i<=k;i++)
	{
		int x=e[i].x,y=e[i].y+n;
		if(findfa(x)==findfa(y))
		{
			if(g[x]^g[y]^e[i].w)
				return 0;
		}
		int fx=findfa(x),fy=findfa(y);
		g[fx]=g[x]^g[y]^e[i].w;
		f[fx]=fy;
	}
	int cnt=0;
	for(int i=1;i<=N;i++)
		if(findfa(i)==i)
			cnt++;
	return poww(2,cnt-1);
}

int w,ans;

int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=k;i++)
	{
		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
		if(e[i].x==1&&e[i].y==1)
		{
			w=i;
			continue;
		}
		if(!((e[i].x&1)|(e[i].y&1))) e[i].w^=1;
	}
	if(w)
	{
		if(e[w].w)
			for(int i=1;i<=k;i++) e[i].w^=1;
		ans=cal();
	}
	else
	{
		ans=cal();
		for(int i=1;i<=k;i++) e[i].w^=1;
		(ans+=cal())%=mod;
	}
	cout<<ans;	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值