[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\)
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