题目链接

(Gym) https://codeforces.com/gym/101471
(BZOJ) 大人,时代变了

题解

又去膜了题解 orz
上来千万不要胡思乱想什么一个点扩展到周围九个点异或叠加之类的诡异东西。。。
考虑如何从某一个时刻的状态反推上一个时刻的状态(假设这一个时刻为 \(a\) 数组、上一个时刻为 \(b\) 数组):注意到下一个时刻的图形范围会比上一个时刻往四个方向都扩展出一圈,那么可以从左下角开始遍历所有 \((i,j)\),每次用 \(a_{i,j}\) 和之前算出的 \(8\)\(b\) 值推得 \(b_{i+1,j+1}\) 的值。然后每做完一行检查一下最后两个 \(a\) 值是否符合,最后再检查最后两行 \(a\) 值是否符合。
但是现在要处理反转至多一个格子的问题。于是考虑 \(a\) 数组一个格子的反转会给 \(b\) 数组带来什么影响,实际上发现 \(a_{i,j}\) 的反转会在下一行导致 \(b_{i+1,k}\) (\(k\le j\)\((k-j)\) 不是 \(3\) 的倍数)反转。那么如果在 \(b\) 数组第 \(i\) 行出了问题,那么说明 \(a\) 数组第 \((i-1)\) 行一定有问题。
这时一个比较难想到的点是,尽管我们这样只能确定有问题的位置在哪一行,但我们可以对列再做一次同样的过程,确定有问题的位置在哪一列。当然这里仅限于前 \((n-2)\)\((m-2)\) 列。
那么如果前 \((n-2)\)\((m-2)\) 列有出问题的格子,就将其反转;否则我们求出的 \(b_{i,j}\) 一定没有问题(如果有问题的话肯定会影响前 \((n-2)\)\((m-2)\) 列的至少一个格子),所以拿它去 check 一下就可以了。
还有个小问题是上一个时刻的状态有可能比这个时刻的少了不止两行两列,所以需要判一下能否缩边界。
时间复杂度 \(O((n+m)^3)\).

代码

#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define x first
#define y second
#define iter iterator
#define riter reverse_iterator
#define y1 Lorem_ipsum_
#define tm dolor_sit_amet_
using namespace std;

inline int read()
{
	int x = 0,f = 1; char ch = getchar();
	for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
	return x*f;
}

const int mxN = 300;
int n,m,lx,rx,ly,ry;
char a[mxN+3][mxN+3],b[mxN+3][mxN+3];

int main()
{
	m = read(),n = read();
	for(int i=1; i<=n; i++) {scanf("%s",a[i]+1); for(int j=1; j<=m; j++) a[i][j] = (a[i][j]=='.'?0:1);}
	lx = 1,rx = n,ly = 1,ry = m;
	while(rx-lx+1>2&&ry-ly+1>2)
	{
		#define check(i,j) (b[i-1][j-1]^b[i-1][j]^b[i-1][j+1]^b[i][j-1]^b[i][j]^b[i][j+1]^b[i+1][j-1]^b[i+1][j]^b[i+1][j+1])==a[i][j]
		int wx = 0,wy = 0;
		for(int i=lx-1; i<=rx+1; i++) for(int j=ly-1; j<=ry+1; j++) b[i][j] = 0;
		for(int i=lx+1; i<=rx-1; i++)
		{
			for(int j=ly+1; j<=ry-1; j++) {b[i][j] = (a[i-1][j-1]^b[i-2][j-2]^b[i-2][j-1]^b[i-2][j]^b[i-1][j-2]^b[i-1][j-1]^b[i-1][j]^b[i][j-2]^b[i][j-1]);}
			if(!check(i-1,ry-1)||!check(i-1,ry)) {wx = i-1; break;}
		}
		for(int j=ly+1; j<=ry-1; j++)
		{
			for(int i=lx+1; i<=rx-1; i++) {b[i][j] = (a[i-1][j-1]^b[i-2][j-2]^b[i-2][j-1]^b[i-2][j]^b[i-1][j-2]^b[i-1][j-1]^b[i-1][j]^b[i][j-2]^b[i][j-1]);}
			if(!check(rx-1,j-1)||!check(rx,j-1)) {wy = j-1; break;}
		}
		if(wx==0||wy==0)
		{
			for(int i=lx; i<=rx; i++)
			{
				bool found = false;
				for(int j=ly; j<=ry; j++)
				{
					if(!check(i,j)) {wx = i,wy = j; a[i][j] ^= 1;}
				}
				if(found) {break;}
			}
		}
		else
		{
			a[wx][wy] ^= 1;
		}
		bool ok = true;
		for(int i=lx+1; i<=rx-1; i++)
		{
			for(int j=ly+1; j<=ry-1; j++) {b[i][j] = (a[i-1][j-1]^b[i-2][j-2]^b[i-2][j-1]^b[i-2][j]^b[i-1][j-2]^b[i-1][j-1]^b[i-1][j]^b[i][j-2]^b[i][j-1]);}
			if(!check(i-1,ry-1)||!check(i-1,ry)) {ok = false; break;}
		}
		for(int i=rx-1; i<=rx; i++)
		{
			for(int j=ly; j<=ry; j++)
			{
				if(!check(i,j)) {ok = false; break;}
			}
			if(!ok) {break;}
		}
		if(!ok)
		{
			a[wx][wy] ^= 1;
			break;
		}
		while(lx<rx)
		{
			bool ok = true;
			for(int j=ly; j<=ry; j++) if(b[lx][j]) {ok = false; break;}
			if(ok) {lx++;} else {break;}
		}
		while(lx<rx)
		{
			bool ok = true;
			for(int j=ly; j<=ry; j++) if(b[rx][j]) {ok = false; break;}
			if(ok) {rx--;} else {break;}
		}
		while(ly<ry)
		{
			bool ok = true;
			for(int i=lx; i<=rx; i++) if(b[i][ly]) {ok = false; break;}
			if(ok) {ly++;} else {break;}
		}
		while(ly<ry)
		{
			bool ok = true;
			for(int i=lx; i<=rx; i++) if(b[i][ry]) {ok = false; break;}
			if(ok) {ry--;} else {break;}
		}
		for(int i=lx; i<=rx; i++) for(int j=ly; j<=ry; j++) a[i][j] = b[i][j];
	}
	for(int i=lx; i<=rx; i++) {for(int j=ly; j<=ry; j++) printf("%c",a[i][j]==0?'.':'#'); puts("");}
	return 0;
}