BZOJ 2303: [Apio2011]方格染色 [并查集 数学!]
2017-03-21 16:26
309 查看
题意:
$n*m:n,m \le 10^6$的网格,每个$2 \times 2$的方格必须有1个或3个涂成红色,其余涂成蓝色
有一些方格已经有颜色
求方案数
太神了!!!花我三节课
首先想了一下只有两行,发现可以直接$f[i][3]\ DP$出来,每一列放的方案只与上一列有关
如果有多行呢,我们可以把上一列放的状态状压$f[i][s]$,然后枚举转移
复杂度爆炸
好,看一眼题解
woc题解说的些什么东西根本看不懂,还是自己想吧
发现,貌似一个状态只有两个后继状态唉,就是说这一列的右面一列只有两种放法是合法的
数学归纳法证一下,两行的情况每种列的放法有两个后继,设n行成立,那么n+1行的下一列选或不选就已经确定了...好像成立唉!
并且这两个后继还是每个位置都相反的!
总算看明白题解那句:
如果确定了第一行,接下来的每一行只会是 1.上一行所有奇数列异或1后得到 2.上一行所有偶数列异或1后得到 (这里把之前的行列倒换了)
其实可以直观理解,因为要保证是奇性啊
这样的话,不考虑已经涂色的,方案数就是第一行的方案数*(行数-1)$2^{n+m-1}$了
考虑涂色!
首先,每个有涂色的行两个后继状态只有一个合法了
再考虑这一行的涂色对第一行的影响,如果有一行两个位置$x,y$已经涂色,因为只有那两种变换所以:
$1.\ x,y同奇偶,每行都必须同色$
$2.\ x,y异奇偶,跟这一行同奇偶的行必须同色,异奇偶的行必须异色$
用个种类并查集就可以判断无解了!
方案数?把有关系限制的列连起来,求连通块数就行了
注意第一行如果有已经涂色的,颜色就直接确定了而不是同色或者异色,所以包含他们的连通块不能再考虑
$n*m:n,m \le 10^6$的网格,每个$2 \times 2$的方格必须有1个或3个涂成红色,其余涂成蓝色
有一些方格已经有颜色
求方案数
太神了!!!花我三节课
首先想了一下只有两行,发现可以直接$f[i][3]\ DP$出来,每一列放的方案只与上一列有关
如果有多行呢,我们可以把上一列放的状态状压$f[i][s]$,然后枚举转移
复杂度爆炸
好,看一眼题解
woc题解说的些什么东西根本看不懂,还是自己想吧
发现,貌似一个状态只有两个后继状态唉,就是说这一列的右面一列只有两种放法是合法的
数学归纳法证一下,两行的情况每种列的放法有两个后继,设n行成立,那么n+1行的下一列选或不选就已经确定了...好像成立唉!
并且这两个后继还是每个位置都相反的!
总算看明白题解那句:
如果确定了第一行,接下来的每一行只会是 1.上一行所有奇数列异或1后得到 2.上一行所有偶数列异或1后得到 (这里把之前的行列倒换了)
其实可以直观理解,因为要保证是奇性啊
这样的话,不考虑已经涂色的,方案数就是第一行的方案数*(行数-1)$2^{n+m-1}$了
考虑涂色!
首先,每个有涂色的行两个后继状态只有一个合法了
再考虑这一行的涂色对第一行的影响,如果有一行两个位置$x,y$已经涂色,因为只有那两种变换所以:
$1.\ x,y同奇偶,每行都必须同色$
$2.\ x,y异奇偶,跟这一行同奇偶的行必须同色,异奇偶的行必须异色$
用个种类并查集就可以判断无解了!
方案数?把有关系限制的列连起来,求连通块数就行了
注意第一行如果有已经涂色的,颜色就直接确定了而不是同色或者异色,所以包含他们的连通块不能再考虑
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> using namespace std; #define pii pair<int, int> #define MP make_pair #define fir first #define sec second const int N=1e6+5, P=1e9; typedef long long ll; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; } int n, m, k, c , p, x, y; struct meow{int r, c;}t; vector<meow> q ; int fa ; int find(int x) {return x==fa[x] ? x : fa[x]=find(fa[x]);} struct UFS{ int fa , val ; int find(int x) { if(x == fa[x]) return x; int root = find(fa[x]); val[x] ^= val[fa[x]]; return fa[x] = root; } bool Union(int x, int y, int p) { int f1 = find(x), f2 = find(y); if(f1 != f2) { fa[f1] = f2; val[f1] = val[x]^val[y]^p; } else if((val[x]^val[y]) != p) return false; return true; } }F; int fix , mark ; int Pow(ll a, int b) { ll ans=1; for(; b; b>>=1, a=a*a%P) if(b&1) ans=ans*a%P; return ans; } int main() { freopen("in","r",stdin); n=read(); m=read(); k=read(); for(int i=1; i<=k; i++) { x=read(), t.r=read(), t.c=read(), q[x].push_back(t); mark[x] = 1; if(x == 1) fix[t.r] = 1; } for(int i=1; i<=m; i++) fa[i] = F.fa[i] = i; for(int i=1; i<=n; i++) for(int j=1; j<(int)q[i].size(); j++) { int a = q[i][j-1].c, b = q[i][j].c, x=q[i][j-1].r, y=q[i][j].r; int f1 = find(x), f2 = find(y); fa[f1] = f2; if(fix[f1]) fix[f2] = 1; int p = a^b; if((x&1) != (y&1)) p ^= (i-1)&1; if(!F.Union(x, y, p)) {puts("0"); return 0;} } int ans = 0; for(int i=2; i<=n; i++) ans += !mark[i]; for(int i=1; i<=m; i++) if(fa[i]==i && !fix[i]) ans++; printf("%d\n", Pow(2, ans)); }
相关文章推荐
- [BZOJ]2303: [Apio2011]方格染色 并查集
- BZOJ 2303: [Apio2011]方格染色 并查集神题
- bzoj 2303: [Apio2011]方格染色【并查集】
- [BZOJ 2303][Apio2011]方格染色:并查集
- bzoj 2303: [Apio2011]方格染色 (并查集)
- BZOJ_2303_[Apio2011]方格染色 _并查集
- 【bzoj 2303】【Apio2011】方格染色
- bzoj 2303 Apio2011 方格染色
- BZOJ 2303: [Apio2011]方格染色 题解
- bzoj 2303: [Apio2011]方格染色
- BZOJ 2303 [Apio2011]方格染色
- [BZOJ2303][Apio2011]方格染色(数学相关+加权并查集)
- BZOJ2303 APIO2011方格染色(并查集)
- [BZOJ2303][APIO2011]方格染色 异或+并查集
- 【BZOJ2303】【Apio2011】方格染色 异或方程+并查集
- 2303: [Apio2011]方格染色
- [杂题 异或 带权并查集] BZOJ2303: [Apio2011]方格染色
- [BZOJ2303]-[Apio2011]方格染色-并查集+题目性质
- [APIO2011]方格染色
- [Apio2011]方格染色