2303: [Apio2011]方格染色
2016-09-16 23:52
369 查看
2303: [Apio2011]方格染色
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 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 32 2 1
1 2 0
2 3 1
Sample Output
8HINT
数据为国内数据+国际数据+修正版鸣谢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; }
相关文章推荐
- bzoj 2303: [Apio2011]方格染色【并查集】
- [BZOJ]2303: [Apio2011]方格染色 并查集
- BZOJ_2303_[Apio2011]方格染色 _并查集
- bzoj 2303: [Apio2011]方格染色
- 【bzoj 2303】【Apio2011】方格染色
- BZOJ 2303: [Apio2011]方格染色 [并查集 数学!]
- [BZOJ 2303][Apio2011]方格染色:并查集
- bzoj 2303: [Apio2011]方格染色 (并查集)
- bzoj 2303 Apio2011 方格染色
- BZOJ 2303 [Apio2011]方格染色
- BZOJ 2303: [Apio2011]方格染色 题解
- BZOJ 2303: [Apio2011]方格染色 并查集神题
- BZOJ2303: [Apio2011]方格染色
- [杂题 异或 带权并查集] BZOJ2303: [Apio2011]方格染色
- [BZOJ2303]-[Apio2011]方格染色-并查集+题目性质
- [Apio2011]方格染色
- [Apio2011]方格染色
- BZOJ2303 APIO2011方格染色
- BZOJ2303 APIO2011方格染色(并查集)
- 【BZOJ2303】【Apio2011】方格染色 异或方程+并查集