[bzoj2303][Apio2011]方格染色
Description
Sam和他的妹妹Sara有一个包含n×m个方格的表格。她们想要将其的每个方格都染成红色或蓝色。
出于个人喜好,他们想要表格中每个2×2的方形区域都包含奇数个(1 个或 3 个)红色方格。
可是昨天晚上,有人已经给表格中的一些方格染上了颜色!现在Sam和Sara非常生气。不过,他们想要知道是否可能给剩下的方格染上颜色,使得整个表格仍然满足她们的要求。如果可能的话,满足他们要求的染色方案数有多少呢?
Input
输入的第一行包含三个整数n,m和k,分别代表表格的行数、列数和已被染色的方格数目。
之后的k行描述已被染色的方格。其中第 i 行包含三个整数 \(x_i,y_i,c_i\),分别代表第 i 个已被染色的方格的行编号、列编号和颜色。\(c_i\) 为 1 表示方格被染成红色,\(c_i\) 为 0 表示方格被染成蓝色。
Output
输出一个整数,表示可能的染色方案数目 W 模 \(10^9\)得到的值。
Sample Input
3 4 3
2 2 1
1 2 0
2 3 1
Sample Output
8
HINT
\(2\leq n,m\leq10^6,0\leq k\leq10^6,1\leq x_i\leq n,1\leq y_i\leq m\).
Solution
设红色为1,蓝色为0,问题约束可以转化成要求每个2×2的方形区域的异或和为1.
如果第一行已经确定,那么后面的每一行要么是上一行的奇数列 xor 1,要么是上一行的偶数列 xor 1.那么方案数为 \(\large{2^{空行数}}\).
现在需要确认是否存在这样的合法的第一行,也就是确认每两个格子间的颜色异或关系是否矛盾.
对于每个同在第i行的已染色的格子\(x,y\),如果它们列数同奇偶,则它们在第一行的关系为\(c_x\;xor\;c_y\); 如果它们列数不同奇偶,则它到第一行一共做了(i-1)变换,它们在第一行的关系为\(c_x\;xor\;c_y\;xor\;(i-1)\).
然后用并查集维护列数,合并同行的已染色的格子,记录其与父亲的异或关系(方便O(1)求出同连通块的格子间的异或关系,判合法性).第一行的方案数即为 \(\large{2^{第一行未染色的连通块数}}\).
#define N 1000005
#define M 1000000000
typedef long long ll;
struct grid{
int x,y,c;
bool friend operator <(grid a,grid b){
if(a.x!=b.x) return a.x<b.x;
return a.y<b.y;
}
}a[N];
int c[N]/*col[1][i]^col[1][f[i]]*/,f[N],n,m,k,tot;
bool b[N],v[N];
inline int gf(int k){
if(f[k]==k) return k;
int fa=gf(f[k]);
c[k]^=c[f[k]];
return f[k]=fa;
}
inline bool chk(int x,int y,int t){
int p=gf(x),q=gf(y);
if(p^q){
if(b[p]||b[q]) b[p]=b[q]=true;
f[p]=q;c[p]=c[x]^c[y]^t;
return true;
}
else return (c[x]^c[y])==t;
}
inline int po(int x,int k){
int ret=1;
while(k){
if(k&1) ret=1ll*ret*x%M;
x=1ll*x*x%M;k>>=1;
}
return ret;
}
inline void Aireen(){
n=read();m=read();k=read();
for(int i=1;i<=k;++i){
a[i]=(grid){read(),read(),read()};
if(a[i].x==1) b[a[i].y]=true;
v[a[i].x]=true;
}
sort(a+1,a+1+k);
for(int i=1;i<=m;++i) f[i]=i;
for(int i=2,x,y,t;i<=k;++i){
while(a[i].x==a[i-1].x){
x=a[i].y;y=a[i-1].y;
t=a[i].c^a[i-1].c;
if((x&1)^(y&1)) t^=((a[i].x-1)&1);
if(!chk(x,y,t)){
puts("0");return;
}
++i;
}
}
for(int i=1;i<=m;++i)
if(gf(i)==i&&!b[i]) ++tot;
for(int i=2;i<=n;++i)
if(!v[i]) ++tot;
printf("%d\n",po(2,tot));
}
2017-05-03 17:56:48