CF1844E. Great Grids

题目大意

有一个n*m的网格图,需要在每个格子内部填入A~C,要求满足:

① 每个2*2的小方格都要有ABC
② 边相邻格子内字母不同

给出初始若干格子相同(满足角相邻)的限制,判断是否存在合法解

2<=n,m<=2e3

题解

神必题……

首先假设给2*2的格子内角相邻的相同格子连斜边,则会连出一个图,每个2*2格子内都要有一条连边

然后在这个图里连通的都是同一个字母,所以会有一些连边情况不合法,比如

这样,则实际上外面四个圆圈都相等,所以会连一下,与右上的边冲突

显然所有连边同向合法,然后根据观察可得,将一个合法图的斜边进行任意行/列翻转仍然合法

所以可以根据行/列是否翻转设01状态,然后用给出的限制来对行/列状态连边(相同/相异),最后dfs判断是否有矛盾即可

证明:
可以设ABC对应012,然后对边相邻的格子连横向/纵向的边,边权为(上-下)%3 or (左-右)%3

然后观察发现一个2*2格子内,上下和左右的边权分别相等(确定一行/列的状态,只能是1/2),且当正对角线相同时上下=左右,反对角线相同时上下≠左右

把差值1/2变成0/1,设为行/列的权值;两种边决定行列权值相同/相异,则和上面差不多了

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;
 
int T,n,m,K,i,j,k,l,x,y;
int X1,Y1,X2,Y2;
int a[80001][3],ls[40001],len;
int f[40001];
bool ans;
 
void New(int x,int y,int z)
{
	++len;
	a[len][0]=y;
	a[len][1]=ls[x];
	ls[x]=len;
	a[len][2]=z;
}
 
void dfs(int t)
{
	int i;
	
	for (i=ls[t]; i; i=a[i][1])
	if (f[a[i][0]]==-1)
	{
		f[a[i][0]]=f[t]^a[i][2];
		dfs(a[i][0]);
	}
	else
	if (f[a[i][0]]!=(f[t]^a[i][2]))
	ans=0;
}
 
int main()
{
	scanf("%d",&T);
	for (;T;--T)
	{
		len=0;
		scanf("%d%d%d",&n,&m,&K);
		fo(i,1,n+m) f[i]=-1,ls[i]=0;
		
		fo(i,1,K)
		{
			scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);
			
			x=min(X1,X2);
			y=min(Y1,Y2);
			if (x==X1 && y==Y1 || x==X2 && y==Y2) //1
			{
				New(x,n+y,0);
				New(n+y,x,0);
			}
			else //2
			{
				New(x,n+y,1);
				New(n+y,x,1);
			}
		}
		
		ans=1;
		fo(i,1,n+m)
		if (f[i]==-1)
		f[i]=0,dfs(i);
		
		if (ans)
		cout<<"YES"<<endl;
		else
		cout<<"NO"<<endl;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章