2303: [Apio2011]方格染色

来源:互联网 发布:数据库管理员是什么 编辑:程序博客网 时间:2024/04/30 10:41

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;}

0 0