您的位置:首页 > 其它

2303: [Apio2011]方格染色

2016-09-16 23:52 369 查看

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: