agc069b

思路

取两个排列 。假设第一步问 返回是,接下来问 。如果某一步问到了是,就再一步把 分出来。最后剩一个问题和 ,此时三个位置要求至少存在一个 。如果第一步问 返回否,删掉 一行一列进入 的子问题。当 时合法。

等价于 次删掉一行一列,要求这一行一列中至少有一个 。套路的对每个 连边 。对于每个连通块,找出一颗生成树,从叶子开始连起,最后根不要了,即能找出 对一行一列。如果 就合法了。

然后写出来发现 WA 个点就破防了!特别的,当 且去到了 的全 矩阵,剩两个问题时,可以问矩阵以外的位置排除一行或一列,所以 时, 就合法了。

code

int n;
char s[maxn];
int a[maxn][maxn];
int f[maxn<<1],siz[maxn<<1];
int fd(int x){
	if(f[x]==x)return x;
	return f[x]=fd(f[x]);
}
void work(){
	n=read();
	for(int i=1;i<=n;i++){
		scanf("%s",s+1);
		for(int j=1;j<=n;j++)a[i][j]=(s[j]=='1');
	}
	for(int i=1;i<=n*2;i++)f[i]=i,siz[i]=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)if(!a[i][j])f[fd(i)]=fd(j+n);
	}
	for(int i=1;i<=2*n;i++)siz[fd(i)]++;
	int ans=0;
	for(int i=1;i<=2*n;i++)if(fd(i)==i)ans+=siz[i]-1;
	if(ans>=n-1||(n>2&&ans>=n-2))puts("Yes");
	else puts("No");
}