loading

P10085 [GDKOI2024 提高组] 染色

题意

有一个 \(2^n\times 2^n\) 的 01 矩阵,初始全是 0。你现在可以执行若干次操作,每一次操作会选择一个位置 \((x,y),0\le x,y<2^n\),将 \((x,y),(x-1,y),(x+1,y),(x,y-1),(x,y+1)\) 全部异或 1,这里我们定义 \(-1=2^n-1\)

给定另一个 01 矩阵,求是否能通过若干次操作将初始 01 矩阵转化为给出的矩阵。无解输出 -1。

\(n\le 11\)

分析

我们称题面给的这种操作为“第零标记”。

我们考虑将标记的范围扩大:

.....    ..*..    ..*..    ..*..    ..*..
..*..    .*.*.    ...*.    ...*.    .....
.***. -> .*.*. -> *.**. -> *..*. -> *.*.*
..*..    ..*..    .**..    ...*.    .....
.....    .....    .....    ..*..    ..*..

通过以上操作,我们能将标记的范围拓展到离中心点 \(2^1=2\) 的距离,我们称之为“第一标记”。

和上面的方式相同,我们也可以通过四次“第一标记”获得标记范围距离中心点 \(2^2=4\) 的距离的标记,即“第二标记”。

注意到第一行和最后一行、第一列和最后一列连通,并且矩形边长为 \(2^n\),因此第 \(n-1\) 标记中上下两个标记的位置重合,左右也同理,所以对一个点使用第 \(n-1\) 标记就相当于单独取反一个位置,因此原问题一定有解。但是对一个点打上第 \(n-1\) 标记的时间复杂度为 \(O(2^{2n}K)\),其中 \(K\) 为第 \(n-1\) 标记所包含的第零标记数量,考虑优化复杂度。

发现对一个点重复打任何一级标记都会让他们抵消,我们考虑归纳地解决问题,假设我们现在已经有了第 \(d+1\) 标记的覆盖对象,那么我们需要将该点以及该点上下左右距离该点 \(2^{d-1}\) 远的点都要打上第 \(d\) 标记。由于每种标记都只会打上一遍(两遍以上会抵消),所以这么做的时间复杂度 \(O(2^{2n}n)\),可能需要卡常。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<functional>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<ctime>
#include<random>
#include<array>
#include<cassert>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0)
#define OTIE cout.tie(0)
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define un using namespace
#define il inline
#define all(x) x.begin(),x.end()
#define mem(x,y) memset(x,y,sizeof x)
#define popc __builtin_popcountll
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) ((x)&-(x))
#define lson(x) ((x)<<1)
#define rson(x) ((x)<<1|1)
//#define double long double
//#define int long long
//#define int __int128
using namespace std;
using i64=long long;
using u64=unsigned long long;
using pii=pair<int,int>;
template<typename T1,typename T2>inline void ckmx(T1 &x,T2 y){x=x>y?x:y;}
template<typename T1,typename T2>inline void ckmn(T1 &x,T2 y){x=x<y?x:y;}
inline auto rd(){
	int qwqx=0,qwqf=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')qwqf=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){qwqx=(qwqx<<1)+(qwqx<<3)+ch-48;ch=getchar();}return qwqx*qwqf;
}
template<typename T>inline void write(T qwqx,char ch='\n'){
	if(qwqx<0){qwqx=-qwqx;putchar('-');}
	int qwqy=0;static char qwqz[40];
	while(qwqx||!qwqy){qwqz[qwqy++]=qwqx%10+48;qwqx/=10;}
	while(qwqy--)putchar(qwqz[qwqy]);if(ch)putchar(ch);
}
bool Mbg;
const int maxn=2e5+5,inf=0x3f3f3f3f;
const int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n,m;
bool a[2][1<<11][1<<11];
inline void solve_the_problem(){
	n=rd(),m=1<<n;
	rep(i,0,m-1)rep(j,0,m-1)a[(n&1)^1][i][j]=rd();
	per(d,n-1,1){
		const int t=d&1;
		rep(i,0,(1<<n)-1)rep(j,0,(1<<n)-1)if(a[t][i][j]){
			a[t][i][j]=0,a[t^1][i][j]^=1;
			rep(k,0,3){
				int tx=(i+(1<<(d-1))*dx[k]%m+m)%m,ty=(j+(1<<(d-1))*dy[k]%m+m)%m;
				a[t^1][tx][ty]^=1;
			}
		}
	}
	vector<pii>ans;
	rep(i,0,(1<<n)-1)rep(j,0,(1<<n)-1)if(a[0][i][j])ans.pb(mp(i,j));
	write(ans.size());
	for(pii i:ans)write(i.fi,32),write(i.se);
}
bool Med;
signed main(){
//	freopen("out.out","w",stdout);
	fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
	int _=1;
	while(_--)solve_the_problem();
}
/*

*/

posted @ 2025-05-28 15:27  dcytrl  阅读(12)  评论(0)    收藏  举报