CF1592F1 Alice and Recoloring 1

CF1592F1 Alice and Recoloring 1

题目

给定一个 \(n\)\(m\) 列的目标矩阵,矩阵元素只有 W 或 B ,并且你有一个初始矩阵,元素全为 W 。

现在你可以矩阵实施以下操作:

  1. 使用一块钱,选定一个包含 \((1,1)\) 的子矩阵,把矩阵中的元素全部反转( W 变 B , B 变 W )。
  2. 使用两块钱,选定一个包含 \((n,1)\) 的子矩阵,把矩阵中的元素全部反转。
  3. 使用四块钱,选定一个包含 \((1,m)\) 的子矩阵,把矩阵中的元素全部反转。
  4. 使用三块钱,选定一个包含 \((n,m)\) 的子矩阵,把矩阵中的元素全部反转。

现在需要你求出把初始矩阵变为目标矩阵最少需要几块钱。

思路

将初始矩阵变为目标矩阵等价于将目标矩阵变为初始矩阵(元素全为W).

我们用数组\(map_{n,m}\)存图,某一位为\(1\)表示目标矩阵上该位为B,\(0\)表示为W.特别地,边界上为\(0\).

定义数组\(sum_{n,m}\),\(sum_{i,j}=map_{i,j}\oplus map_{i+1,j}\oplus map_{i,j+1}\oplus map_{i+1,j+1}\).

\(map\)所有元素变为\(0\)等价于\(sum_{n,m}\)所有元素变为\(0\).

考虑四种操作对\(sum\)的影响.

首先,操作2,3是没有用的,可以被两次操作1代替.

为了方便,定义四元组\((x_1,y_1,x_2,y_2)\)表示左上角,右下角分别为\((x_1,y_1)\),\((x_2,y_2)\)的子矩阵.

若我们选择\((1,1,x,y)\)的矩阵翻转,仅有\(sum_{x,y}\)取反,花费一元.

若我们选择\((x,y,n,m)\)的矩阵反转,则\(sum_{x-1,y-1}\),\(sum_{x-1,m}\),\(sum_{n,y-1}\),\(sum_{n,m}\)取反,花费三元,改变四个格子.但是若进行两次操作4,\(sum_{n,m}\)取反两次,即不变,花费了6元改变了6个格子,这样我们不如用操作1.

统计下\(sum\)数组中\(1\)的数量,判断能否使用操作4即可.

代码

#include <iostream>
#include <cstdio>
using namespace std;
int read() {
	int re = 0;
	char c = getchar();
	bool negt = false;
	while(c < '0' || c > '9')negt |= (c == '-') , c = getchar();
	while(c >= '0' && c <= '9')re = (re << 1) + (re << 3) + c - '0' , c = getchar();
	return negt ? -re : re;
}
int readc() {
	char c = getchar();
	while(c != 'W' && c != 'B')c = getchar();
	return c;
}

const int N = 510;
int n , m;
bool map[N][N];
bool sum[N][N];
int main() {
	n = read() , m = read();
	for(int i = 1 ; i <= n ; i++)
		for(int j = 1 ; j <= m ; j++)
			map[i][j] = (readc() == 'B');
	int ans = 0;
	for(int i = n ; i > 0 ; i--)
		for(int j = m ; j > 0 ; j--)
			ans += (sum[i][j] = map[i + 1][j] ^ map[i][j + 1] ^ map[i + 1][j + 1] ^ map[i][j]);
	if(sum[n][m])
		for(int i = 1 ; i < n ; i++)
			for(int j = 1 ; j < m ; j++)
				if(sum[i][j] && sum[i][m] && sum[n][j]) {
					cout << --ans;
					return 0;
				}
	cout << ans;
	return 0;
}
原文地址:https://www.cnblogs.com/dream1024/p/15575574.html