P14819 [ICPC 2023 Yokohama R] Color Inversion on a Huge Chessboard 个人题解

题目链接

题目大意

给定一个黑白相间的图,其中第 \(i\) 行第 \(j\) 列的位置如果 \((i+j)\) 为奇数,则这个位置为黑色,否则为白色。可以对这个图进行行取反和列取反操作,要求在每一次操作后输出当前图中剩余的块的个数。

Solution

首先初始的时候由于相邻的块各不相同,于是一共有 \(n^2\) 个块。我们设 \(r_{i}\) 数组为第 \(i\) 行进行取反操作的次数,\(c_{i}\) 数组为第 \(j\) 列进行取反操作的次数,其中奇数次为 \(1\),偶数次为 \(0\)。所以第 \(i\) 行第 \(j\) 列的位置的颜色就等于 \(((i+j)\bmod 2)\oplus r_{i} \oplus c_{j}\)(其中 \(1\) 为黑色,\(0\) 为白色),我们通过这个式子去研究相邻两行或列的关系。

首先看相邻的两行,我们发现上面那个式子也可以写成 \(((i+j)\bmod2+r_{i}+c_{j})\bmod2\),如果同一列上相邻的两行(如 \((i,j)\)\((i+1,j)\))颜色相同时式子可以写成 \((i+j)\bmod2+r_{i}+c_{j}\equiv (i+j+1)\bmod2+r_{i+1}+c_{j}\pmod2\),化简可以得到发现当初始颜色一样的时候,如果 \(r_{i}=r_{i+1}\) 则相邻的两行颜色相等,否则颜色相反。同理可得如果 \(c_{j}=c_{j+1}\) 则相邻的两列颜色相等,否则颜色相反。

有了上面那个式子我们就可以判断相邻的两行或两列颜色是否相等,由于是否相等只与其初始颜色异或上 \(r_{i}\)\(c_{j}\) 有关,我们用数组 \(a_{i},b_{j}\) 来表示当前这一位置上行与列上的关系,具体的,我们令 \(a_{i}=(i\bmod2)\oplus r_{i},b_{j}=(j\bmod2)\oplus c_{j}\),这样每次进行取反操作时只需要比较其相邻的 \(a_{i}\)\(b_{j}\) 就行了,然后每次用 \(r_{i}\)\(c_{j}\) 去更新 \(a_{i}\)\(b_{j}\)

最后我们来看如何统计块数,我们上面已经处理了什么时候相邻的两行或列颜色相等,可以通过有多少相邻且不相等的行或列,把他们乘起来就可以了,每次取反的时候用 \(a_{i}\)\(b_{j}\) 取更新就行了。注意,我们是进行的相邻比较,所以最后要先加一在相乘。

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
inline int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0' || c>'9'){
		if(c=='-')
			f=-1;
		c=getchar();
	}
	while(c>='0' && c<='9'){
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
int n=read(),q=read(),a[N],b[N],r[N],c[N];
int cnt1,cnt2;
signed main(){
	for(int i=1;i<=n;i++)
		a[i]=b[i]=i%2;//处理初始颜色 
	for(int i=1;i<n;i++){
		if(a[i]!=a[i+1]) cnt1++;//处理初始时有多少相邻且不同的行 
		if(b[i]!=b[i+1]) cnt2++;//处理初始时有多少相邻且不同的列 
	}
	while(q--){
		string s;
		cin>>s;
		int x=read();
		if(s=="ROW"){
			if(x>1){ 
				if(a[x]==a[x-1]) cnt1++;//如果相等,则在取反之后就不相等了,贡献+1 
				else cnt1--;//否则在取反之后就相等了,共享-1 
			}
			if(x<n){
				if(a[x]==a[x+1]) cnt1++;
				else cnt1--;
			}	
			r[x]^=1;//增加取反的次数 
			a[x]=(x%2)^r[x];//更新a[i] 
		}
		else{
			if(x>1){
				if(b[x]==b[x-1]) cnt2++;
				else cnt2--; 
			}
			if(x<n){
				if(b[x]==b[x+1]) cnt2++;
				else cnt2--;
			}
			c[x]^=1;
			b[x]=(x%2)^c[x];
		}
		printf("%lld\n",(cnt1+1)*(cnt2+1));//最终答案就是行的贡献乘以列的贡献 
	}
	return 0;
}
posted @ 2025-12-22 18:48  See_you_soon  阅读(6)  评论(0)    收藏  举报