1. 程式人生 > 其它 >[bzoj2303][Apio2011]方格染色

[bzoj2303][Apio2011]方格染色

Sam和他的妹妹Sara有一個包含n×m個方格的表格。她們想要將其的每個方格都染成紅色或藍色。 出於個人喜好,他們想要表格中每個2×2的方形區域都包含奇數個(1 個或 3 個)紅色方格。 可是昨天晚上,有人已經給表格中的一些方格染上了顏色!現在Sam和Sara非常生氣。不過,他們想要知道是否可能給剩下的方格染上顏色,使得整個表格仍然滿足她們的要求。如果可能的話,滿足他們要求的染色方案數有多少呢?

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