#C241018B. 游客与染色


#C241018B. 游客与染色

标签(Label)

  • 并查集
  • 观察+分析

网址(Website)

题目详情 - 游客与染色 - Super

题解 - 游客与染色 - Super

题解(Solution)

$\qquad$很重要的性质:知道第 $1$ 行和第 $1$ 列就能知道整个矩阵。

$\qquad$怎么想到的呢?从最开始开始推矩阵,就可以发现规律。

$\qquad$我这个傻货,直接去推矩阵的中间,然后没有发现这个性质。。。。。。

$\qquad$累积经验:做题之前,如果要求情况数,可以先枚举一种情况找规律——手跑一种推所有。

出题者题解

算法分析

算法 1

直接
$2^{nm}$ 次方枚举即可。期望得分 $10$。

算法 2

设 $a_{i,j}$ 为第 $i$ 行 $j$ 列的颜色,对于 $i,j>1$ 有 $a_{i,j} = a_{i-1,j} \oplus a_{i,j-1} \oplus a_{i-1,j-1}$。所以,当我们确定了第一行和第一列时整个矩阵可以被确定。对于空矩阵,任何填入第一行第一列的方式都是合法的,故答案为 $2^{n+m-1}$。 结合算法 1 期望得分 $30$。

算法 3

爆搜枚举第一行第一列的颜色即可。 结合算法 2 期望得分 $45$。

算法 4

观察发现一次涂色即为加入若干个“若 $x$ 行 $1$ 列为 $a$,则 $1$ 行 $y$ 列为 $b$ ”的限制。 把每行每列看作两个点 $u_0, u_1$,共 $2 \times (n+m)$ 个点,表示取值为 $0/1$。把限制看作加入边。则同一个连通块的点必须同时取。我们只需维护连通块个数即可。具体的,设两个点为 $u, v$,则我们连上 $u_0 - v_c, u_1 - v_{1-c}$。若此时存在点 $u$,使得 $u_0, u_1$ 在同一连通块中,则答案为 $0$。上述过程都可以用并查集维护。最后注意 $x=1$ 或 $y=1$ 的情况。时间复杂度 $O(n\alpha(n))$。期望得分 $100$。

代码(Code)

#include<bits/stdc++.h>
#include<vector>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define P pair<int,int> 
#define int long long
#define x first
#define y second
inline int rd(){
	char c;bool f=false;while(!isdigit(c=getchar()))f=c=='-';int x=c^48;
	while(isdigit(c=getchar())){x=(((x<<2)+x)<<1)+(c^48);}return f?-x:x;
}const int inf = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;
const int N = 2012345;
bool ST;

int n,m,q,cnt;
int fa[N];

inline int find(int x){
	if(fa[x]==x) return x;
	return fa[x] = find(fa[x]);
}

void merge(int x,int y){
	x = find(x), y = find(y);
	if(x^y) fa[x] = y,cnt--;
}

bool flag = true;
int pw[N];
void Solve(){
	n = rd(), m = rd(), q = rd(), cnt = 2*(n+m);
	pw[0] = 1;For(i,1,n+m) pw[i] = pw[i-1]*2%mod;
	iota(fa,fa+(n+m)*2+1,0);
	printf("%lld\n",pw[cnt/2-1]);
	while(q--){
		int x = rd(), y = rd()+n, c = rd();
		if(!flag){printf("0\n");continue;}
		if(c) merge(x,y+n+m), merge(x+n+m,y);
		else merge(x,y), merge(x+n+m,y+n+m);
		if(find(x)==find(x+n+m)) flag=0,printf("0\n");
		else printf("%lld\n", pw[cnt/2-1]);
	}
}

bool ED;
signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cerr<<abs(&ST-&ED)/1024./1024.<<"MB\n";
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	int T = 1, Tim = clock();
	while(T--) Solve();	
	return cerr<<"TIME:"<<(clock()-Tim)/1000.,0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录