BZOJ2303: [Apio2011]方格染色

来源:互联网 发布:黑马程序员培训多少钱 编辑:程序博客网 时间:2024/04/27 22:19

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2303

题目简述:有一个包含n × m个方格的表格,每个方格可以涂红色或蓝色,他们想要表格中每个2 × 2的方形区域都包含奇数个(1 个或 3 个)红色方格。有些格子已经被确定颜色,剩下的格子可以自行染色。求满足条件的方案数MOD(10^9)。


哎这数据太弱了,,考试随便写了个。。神坑算法 ,就过了80分,剩下两个点还是因为爆栈。

首先一个没有一个是固定的,答案就是2^(n+m-1)。这个随便搞zhao一gui下lv就行了。记p=n+m-1

神坑算法:先看他给出来的是否有冲突,没有冲突就找他给出来的东西的所有极大联通块。对每个联通块找一个最小的矩形把他包起来,令这个矩形的长宽为a,b

,然后p-=(a+b-1)。。然后所有矩形搞完了就算2^p。  哎哎。。


正规算法:

其实试一下就会发现,奇数行和偶数行分别是有规律的。若第i行是奇数行且i行中第x列和第y列的颜色是一样的,那么所有奇数行的第x列和第y列的颜色都是一样的。偶数行亦然。且一行只要确定了一个,整行就固定了。为了简化问题,所以把所有相同的关系搞到第一二行上去,并查集维护关系(相同或不同)。

再新建两个虚拟点,一个代表红色,一个代表蓝色, 红色蓝色之间连不同!!!!!<-用来判断冲突。!!

如果并查集加的时候有问题。那直接输出0.

第一二行的异同情况搞出来之后,再考虑第一二行的关系,发现同一列颜色上下的关系只可能是 同 不同 同 不同 ....或者 不同 同 不同 同。

分别按两种方法再把刚才处理出来的并查集连上,若没有冲突,再看有几个集合。

若该集合和红蓝虚拟点有链接,说明这个集合的颜色是固定的。答案是*1 ,就是不变。

若和红蓝节点没有连接,说明他有两种方法(10, 01),这时答案*2。

然后把两个情况的答案加起来。

最后还要看3-n行是不是每一行都有限制,若有一行没有限制,那他也有两种颜色选择,所以答案和还要乘一个2^没有限制的行的个数。

他的题解算法就不说了(meikandong)。但应该思路都是基本相同的。


#include <cstdio>#include <algorithm>typedef long long LL;inline int getx(){char c;int x;for (c=getchar();c<'0'||c>'9';c=getchar());for (x=0;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';return x;}struct Point{int x,y;short color;Point(int _x = 0,int _y = 0,short _c = 0):x(_x),y(_y),color(_c){}};bool operator <(const Point &a,const Point &b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}const LL MOD=(int)1e9;const int MAX_N=100005;int fa[MAX_N*2];bool delta[MAX_N*2];int tfa[MAX_N*2];bool tdelta[MAX_N*2];Point a[MAX_N];int n,m,k,p;#define black (2*m+1)#define white (2*m+2)//a==b 0//a!=b 1int getfa(int x){if (fa[x]!=x){int tp=fa[x];fa[x]=getfa(fa[x]);delta[x]=(delta[x]+delta[tp])%2;}return fa[x];}inline bool merge(int x,int y,int c){int A=getfa(x),B=getfa(y);if (A==B){int tp=(delta[x]+2-delta[y])%2;if (tp!=c) return false;}else{fa[A]=B;delta[A]=(2-delta[x]+c+delta[y])%2;}return true;}inline bool work(int l,int r){int row=(a[l].x&1)?0:m;for (int i=l;i<r;++i)if (!merge(row+a[i].y,row+a[i+1].y,a[i].color!=a[i+1].color)) return false;return true;}LL power(LL a,LL b){LL res=1;for (;b;a=a*a%MOD,b>>=1)if (b&1) res=res*a%MOD;return res;}bool pd[MAX_N*2];LL ans=0;bool work2(){for (int i=1;i<=2*m+2;++i) tfa[i]=fa[i],tdelta[i]=delta[i];bool ck1=true,ck2=true;int num=0;for (int i=1;i<=m;++i)if (!merge(i,m+i,(i&1)==1)){ck1=false;break;}if (ck1){for (int i=1;i<=m;++i){int A=getfa(i);if (!pd[A]){pd[A]=true;if (A!=getfa(white)&&A!=getfa(black)) num++;}}ans+=power(2,num);}num=0;for (int i=1;i<=2*m+2;++i) fa[i]=tfa[i],delta[i]=tdelta[i],pd[i]=0;for (int i=1;i<=m;++i)if (!merge(i,m+i,(i&1)==0)){ck2=false;break;}if (ck2){for (int i=1;i<=m;++i){int A=getfa(i);if (!pd[A]){pd[A]=true;if (A!=getfa(white)&&A!=getfa(black)) num++;}}(ans+=power(2,num))%=MOD;}return ck1||ck2;}int main(){freopen("color.in","r",stdin);freopen("color.out","w",stdout);n=getx(),m=getx(),k=getx();for (int i=1;i<=2*m+2;++i) fa[i]=i,delta[i]=0;merge(black,white,1);//这都没加!!! for (int i=1;i<=k;++i)a[i].x=getx(),a[i].y=getx(),a[i].color=getx();std::sort(a+1,a+k+1);int vis=0,last=1;for (int i=1;i<=k;++i) if (a[i].x!=a[i+1].x){if (a[i].x<=2){int f=(a[i].x==1?0:m);for (int j=last;j<=i;++j)if (!merge(f+a[i].y,a[i].color?black:white,0)){printf("0");exit(0);}}else vis++;if (!work(last,i)){printf("0");exit(0);}last=i+1;}p=n-2-vis;if (!work2()) {printf("0");exit(0);}printf("%I64d\n",power(2,p)*ans%MOD);}


0 0
原创粉丝点击