CF1391D 【505】

题目翻译

有一个 \(n \times m\)\(01\) 矩阵,可以修改一些位置,使得矩阵中的所有 长度为偶数的正方形子矩阵里的 \(1\) 的数量为奇数。求出最少的修改次数。

如果无论怎么修改都无法完成,输出 \(-1\)

思路

显然一个 \(4 \times 4\) 的子矩阵可以由 \(4\)\(2 \times 2\) 的矩阵构成。

但是如果这 \(4\)\(2 \times 2\) 的矩阵中 \(1\) 的数量都是奇数,那么 \(4 \times 4\) 大小的矩阵里 \(1\) 的数量就是:奇 \(+\)\(+\)\(+\)\(=\) 偶 ,这显然是自相矛盾的。

所以,当出现了一个 \(4 \times 4\) 大小的子矩阵即 \(n \ge 4\) 时,直接输出 \(-1\) 即可。

而如果没有 \(4 \times 4\) 的矩阵,那么就意味着只要考虑 \(2 \times 2\) 的矩阵。

因为题目告诉我们 \(n\le m\) ,故我们只需要考虑 \(n==1\)\(2\)\(3\) 三种情况 。

可以分开讨论三种情况:

  • \(n == 1\) 时:

    所有情况都满足要求,输出 \(0\)

  • \(n == 2\) 时:

    很容易想到,如果每一个子矩阵都满足要求,那么列与列之间的奇偶关系一定是:奇偶奇偶奇偶奇偶... 或者是:偶奇偶奇偶奇偶奇... 。

    而如果一列转换奇偶性,那么只要修改一次。

    所以可以直接算变为两种情况的代价,然后在这两种情况里取最小值即可。

  • \(n == 3\) 时:

    \(n==2\) 的情况一样,如果每一个子矩阵都满足要求,那么对于每一列的上面两行和下面两行,他们之间的奇偶关系也是互相交错的。

    那么如果一列的上面两行要修改奇偶性,同样可以只修改一次。

    但这一次可以修改在第一行,也可以修改在第二行。如果修改在第一行那么就只有上面两行的奇偶性改变;而如果修改在第二行那么上面两行和下面两行的奇偶性都会改变。

    而在下面两行的修改同理。

    所以只要这一列中,不论是上面两行还是下面两行要转变奇偶性,最多都只要修改一次。

Code

#include<bits/stdc++.h>

using namespace std;

int read()
{
	int ans=0,f=1;
	char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
	return ans*f;
}

const int N=1e6+5;
int n,m,mmap[5][N],ans;
//因为 n<=m 放第一维只要开到3
char s[N];

inline int get_2_ans(int x);
//计算 n=2 时的答案,x 为第一列的奇偶性
  
inline int get_3_ans(int x,int y);
//计算 n=3 时的答案,x 为第一列上面两行的奇偶性,y 为第一列下面两行的奇偶性

int main()
{
	n=read();m=read();
	if(n>=4)
		printf("-1\n");
	else if(n==1)
		printf("0\n");
	else if(n==2) //n==2 的情况
	{
		for(int i=1;i<=n;++i)
		{
			scanf("%s",s+1);
			for(int j=1;j<=m;++j)
				mmap[i][j]=s[j]-'0';
		}
		ans=min(get_2_ans(0),get_2_ans(1));
		printf("%d\n",ans);
	}
	else //n==3 的情况
	{
		for(int i=1;i<=n;++i)
		{
			scanf("%s",s+1);
			for(int j=1;j<=m;++j)
				mmap[i][j]=s[j]-'0';
		}
		ans=0x7fffffff;
 		//枚举每一种奇偶性,统计答案
		ans=min(ans,get_3_ans(0,0));
		ans=min(ans,get_3_ans(1,0));
		ans=min(ans,get_3_ans(0,1));
		ans=min(ans,get_3_ans(1,1));
		printf("%d\n",ans); 
	}
	return 0;
} 

inline int get_2_ans(int x)
{
	int res=0;
	for(int i=1;i<=m;++i)
	{
         // 如果这一列的奇偶性目标不同,修改一次
		if((mmap[1][i]+mmap[2][i])%2!=x)
			res++;
		x=!x; // 转换奇偶性
	}
	return res;
}

inline int get_3_ans(int x,int y)
{
	int res=0;
	for(int i=1;i<=m;++i)
	{
  		// 如果这一列的上面两行或者下丽两行的奇偶性目标不同,修改一次
		if((mmap[1][i]+mmap[2][i])%2!=x)
			res++;
		else if((mmap[2][i]+mmap[3][i])%2!=y)
			res++;
		x=!x;y=!y;  // 转换奇偶性
	}
	return res;
}
posted @ 2020-08-23 20:00  Blackbird137  阅读(74)  评论(0编辑  收藏  举报