1. 程式人生 > >BZOJ2303 APIO2011方格染色(並查集)

BZOJ2303 APIO2011方格染色(並查集)

答案 註意 != truct 方格染色 endif read 根據 tex

  比較難想到的是將題目中的要求看做異或。那麽有ai,j^ai+1,j^ai,j+1^ai+1,j+1=1。瞎化一化可以大膽猜想得到a1,1^a1,j^ai,1^ai,j=(i-1)*(j-1)&1。也就是說,確定第一行和第一列的顏色,就可以確定整個矩陣。現在如果沒有已填的格子的限制,答案就是2n+m-1

  然後考慮已填格子。假設固定了a1,1,那麽其影響到的就是a1,j和ai,1。即要求兩者相同或不同。於是可以把每個格子的染色情況拆成兩個點,根據已填格子將其連邊,同一連通塊內的點只要選擇一個就必須全部選擇。那麽方案數就是2連通塊個數/2。註意特判第一行或第一列格子已填的情況。

  細節比較麻煩,寫完也不知道自己在幹啥。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
    while (c>=0&&c<=
9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define P 1000000000 #define N 100010 int n,m,k,fa[N<<2],color[N<<2]; struct data{int x,y,c; }a[N]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} int solve(int c) { memset(color,0,sizeof(color)); for (int i=1;i<=(n+m-2
<<1);i++) fa[i]=i; for (int i=1;i<=k;i++) if (a[i].x!=1&&a[i].y!=1) if ((a[i].c==c)^(((a[i].x-1)&1)*(a[i].y-1)&1)) fa[find((a[i].x-1<<1)-1)]=find((n+a[i].y-2<<1)-1),fa[find(a[i].x-1<<1)]=find(n+a[i].y-2<<1); else fa[find((a[i].x-1<<1)-1)]=find(n+a[i].y-2<<1),fa[find(a[i].x-1<<1)]=find((n+a[i].y-2<<1)-1); int cnt=0; for (int i=1;i<=n+m-2;i++) if (find((i<<1)-1)==find(i<<1)) return 0; for (int i=1;i<=k;i++) { if (a[i].x==1&&a[i].y==1){if (a[i].c!=c) return 0;} else { if (a[i].y==1) { if (color[find((a[i].x-1<<1)-a[i].c)]!=-1) color[find((a[i].x-1<<1)-a[i].c)]=1;else return 0; if (color[find((a[i].x-1<<1)-(a[i].c^1))]!=1) color[find((a[i].x-1<<1)-(a[i].c^1))]=-1;else return 0; } if (a[i].x==1) { if (color[find((n+a[i].y-2<<1)-a[i].c)]!=-1) color[find((n+a[i].y-2<<1)-a[i].c)]=1;else return 0; if (color[find((n+a[i].y-2<<1)-(a[i].c^1))]!=1) color[find((n+a[i].y-2<<1)-(a[i].c^1))]=-1;else return 0; } } } for (int i=1;i<=(n+m-2<<1);i++) if (find(i)==i&&!color[i]) cnt++; cnt>>=1; int ans=1;while (cnt--) ans=(ans<<1)%P; return ans; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj2303.in","r",stdin); freopen("bzoj2303.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(),k=read(); for (int i=1;i<=k;i++) a[i].x=read(),a[i].y=read(),a[i].c=read(); cout<<(solve(0)+solve(1))%P; return 0; }

BZOJ2303 APIO2011方格染色(並查集)