~~~~~ P3631 [APIO2011] 方格染色 ~~~~~ 总题单链接
思路
~~~~~ 用 1 1 1表示红色, 0 0 0 表示蓝色, c o l [ i ] [ j ] col[i][j] col[i][j] 表示第 i i i 行,第 j j j 列的颜色。发现 i ≥ 2 , j ≥ 2 i\geq 2,j\geq 2 i≥2,j≥2 时, c o l [ i ] [ j ] = c o l [ i − 1 ] [ j − 1 ] ⊕ c o l [ i − 1 ] [ j ] ⊕ c o l [ i ] [ j − 1 ] ⊕ 1 col[i][j] = col[i-1][j-1]\oplus col[i-1][j]\oplus col[i][j-1]\oplus 1 col[i][j]=col[i−1][j−1]⊕col[i−1][j]⊕col[i][j−1]⊕1,所以只要第一行和第一列的颜色确定了,整个矩阵就能确定。
~~~~~ 但这还不够,先不管 ⊕ 1 \oplus 1 ⊕1 画个图看一下:
~~~~~ 发现 a [ i ] [ j ] = a [ 1 ] [ 1 ] ⊕ a [ i ] [ 1 ] ⊕ a [ 1 ] [ j ] a[i][j]=a[1][1]\oplus a[i][1]\oplus a[1][j] a[i][j]=a[1][1]⊕a[i][1]⊕a[1][j],所以每次涂色等同于一个形如一个(若第 i i i行第一列的值是 a a a,则第 j j j 列第一行的值是 b b b)的限制,这里的 a , b ∈ { 0 , 1 } a,b \in{\{0,1\}} a,b∈{0,1},欸,那么 a [ 1 ] [ 1 ] a[1][1] a[1][1] 去哪了,仔细想想,假如这条限制默认 a [ 1 ] [ 1 ] = 0 a[1][1]=0 a[1][1]=0,那 a [ 1 ] [ 1 ] = 1 a[1][1]=1 a[1][1]=1 的情况不就是把 a , b a,b a,b 换一下吗,所以 a [ 1 ] [ 1 ] a[1][1] a[1][1] 在这条限制中其实不重要。
~~~~~ 那么大概就可以往连边和连通块的方向去想了。
~~~~~ 将每行每列视为两个点 u 0 u_0 u0 和 u 1 u_1 u1,表示这一行 / / /列的第一个值选 0 / 1 0/1 0/1。
~~~~~ 对于一次在第 i i i 行,第 j j j 列,颜色为 c c c 的涂色,设 u 0 , u 1 u_0,u_1 u0,u1 表示第 i i i 行表示的两个点, v 0 , v 1 v_0,v_1 v0,v1 表示第 j j j 列表示的两个点,连两条边 u 0 —— v c , u 1 —— v c ⊕ 1 u_0~——~v_c,u_1~——~v_{c\oplus 1} u0 —— vc,u1 —— vc⊕1,连边后一个连通块就必须要一起选了,如果存在一个点使得 u 0 , u 1 u_0,u_1 u0,u1 在一个连通块中,那么答案就是 0 0 0。
~~~~~ 我们还没有考虑 ⊕ 1 \oplus 1 ⊕1,再画一个只考虑 ⊕ 1 \oplus 1 ⊕1的图:
~~~~~ 发现只有 i , j i,j i,j 都为偶数的情况下才会 ⊕ 1 \oplus 1 ⊕1,直接将 c ⊕ 1 c\oplus 1 c⊕1即可。
~~~~~ 我个人认到这里还是比较难理解的,我也想了很久,所以如果你没有理解大可不必着急,慢慢来,再看一遍或者自己动手画图,模拟一下样例。
代码
#include<bits/stdc++.h>
#define ll long long
#define MOD 1000000000
using namespace std;inline ll qmi(ll a,ll b){ll res=1;while(b){if(b&1)(res*=a)%=MOD;(a*=a)%=MOD;b>>=1;}return res;
}ll n,m,Q;inline ll U(ll x,ll y){return(y==0?x:x+n);}
inline ll V(ll x,ll y){return(y==0?x+n*2:x+n*2+m);}struct BJ{ll fas[400005],cnt;void init(){for(ll i=1;i<=2*(n+m);i++)fas[i]=i;cnt=2*(n+m);}inline ll fid(ll p){if(fas[p]!=p)fas[p]=fid(fas[p]);return fas[p];}inline void uni(ll x,ll y){x=fid(x),y=fid(y);if(x!=y)fas[x]=y,cnt--;}
}bj;signed main(){ios::sync_with_stdio(false);cin>>n>>m>>Q;if(n==1||m==1){cout<<qmi(2,n*m-Q);return 0;}bj.init();ll opt=1;while(Q--){ll x,y,c;cin>>x>>y>>c;if(x%2==0&&y%2==0)c^=1;bj.uni(U(x,0),V(y,c));bj.uni(U(x,1),V(y,c^1));if(bj.fid(U(x,0))==bj.fid(U(x,1))||bj.fid(V(y,0))==bj.fid(V(y,1)))opt=0;}cout<<(opt==1?qmi(2,bj.cnt/2-1):0)<<endl;return 0;
}
~~~~~ 侵权必 … \ldots … 算了都没人看,哪来的侵权。考虑给个赞和关注吗?