2303: [Apio2011]方格染色

2303: [Apio2011]方格染色

Time Limit: 20 Sec   Memory Limit: 256 MB
Submit: 1452   Solved: 569
[ Submit][ Status][ Discuss]

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

[ Submit][ Status][ Discuss]

记a[i][j]为(i,j)染色状态
染成红色为1,染成蓝色为0
可以发现,一个符合条件的2*2方块xor为1
一般的,可以推出一个点(i,j),染色合法的条件是,
a[i][j]^a[i-1][j]^a[i][j-1]^a[i-1][j-1] = 1
用这个式子去往前使劲推,,(画几个特例)
发现对于(i,j)有一个是奇数时,有a[i][j] = a[1][j]^a[i][1]^a[1][1]
如果两个都是偶数,那么a[i][j] = a[1][j]^a[i][1]^a[1][1]^1

事实上,还能发现,如果一个矩形的第一行及第一列染色方案确定,
那么整个矩形的染色就唯一了
那么上述两式就变成约束条件
对于每个条件,a[i][j]是已知的,倘若我们确定a[1][1],那么a[1][j]与a[i][1]的关系也就随之确定
即一定相等or一定不等
特别的,这玩意对于(i,j)有一个是1时也成立
如果两个都是1,特判掉即可

那么这一堆的约束就可以看成一个个关系
对于强制要求相同的,我们把他们连在一起,
对于强制要求不同的,还是把他们连在一起~
因为只要有约束关系存在,那么确定了一者以后另一者也就唯一确定

经过了k次的连边,原本第一行与第一列的那些点已经被分割成若干个连通块
除了(1,1)代表点所在的那个块(a[1][1]是通过枚举的),其余每块都有两种选择
假设有tot个块,那么这时候的答案就是2^(tot-1)

对于强制要求不同的,,假如我们先前已经要求它们相同,那么说明不存在合法染色方案
现在还剩一个问题,如何特判???
苟蒻自己写的东西简直WA飞。。。
参考了网上的方法
多维护一个数组g[i],代表i点和它的父亲的关系
0代表相等,1代表不等
并查集的时候顺便维护g数组就行
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 2E6 + 10;
const int mo = 1E9;

int n,m,k,tot,Ans,cnt,fa[maxn],r[maxn],c[maxn],typ[maxn];

int getfa(int x) {return x == fa[x]?x:fa[x] = getfa(fa[x]);}

void Solve(int Now)
{
	for (int i = 1; i <= n + m; i++) fa[i] = i;
	fa[1] = 1 + n;
	for (int i = 1; i <= k; i++) {
		int fr = getfa(r[i]);
		int fc = getfa(c[i] + n);
		int flag = typ[i]^Now;
		if (r[i] % 2 == 0 && c[i] % 2 == 0) flag ^= 1;
		if (!flag && fr != fc) fa[fr] = fc;
	}
	for (int i = 1; i <= k; i++) {
		int fr = getfa(r[i]);
		int fc = getfa(c[i] + n);
		int flag = typ[i]^Now;
		if (r[i] % 2 == 0 && c[i] % 2 == 0) flag ^= 1;
		if (flag && fr == fc) return;
	}
	for (int i = 1; i <= k; i++) {
		int fr = getfa(r[i]);
		int fc = getfa(c[i] + n);
		if (fr != fc) fa[fr] = fc;
	}
	int ans = -1; 
	for (int i = 1; i <= n + m; i++)
		if (i == getfa(i)) {
			if (ans == -1) ans = 1;
			else ans *= 2,ans %= mo;
		}
	if (ans != -1) Ans = (Ans + ans) % mo;
}

int getint()
{
	char ch = getchar();
	int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

int main()
{
	//freopen("2303.in","r",stdin);
	//freopen("2303.out","w",stdout);
	
	n = getint(); 
	m = getint();
	k = getint();
	for (int i = 1; i <= k; i++) {
		r[i] = getint();
		c[i] = getint();
		typ[i] = getint();
	}
	for (int i = 0; i < 2; i++) Solve(i);
	cout << Ans;
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值