题目
给定一个 n n n 行 m m m 列的目标矩阵,矩阵元素只有 W 或 B ,并且你有一个初始矩阵,元素全为 W 。
现在你可以矩阵实施以下操作:
- 使用一块钱,选定一个包含 ( 1 , 1 ) (1,1) (1,1) 的子矩阵,把矩阵中的元素全部反转( W 变 B , B 变 W )。
- 使用两块钱,选定一个包含 ( n , 1 ) (n,1) (n,1) 的子矩阵,把矩阵中的元素全部反转。
- 使用四块钱,选定一个包含 ( 1 , m ) (1,m) (1,m) 的子矩阵,把矩阵中的元素全部反转。
- 使用三块钱,选定一个包含 ( n , m ) (n,m) (n,m) 的子矩阵,把矩阵中的元素全部反转。
现在需要你求出把初始矩阵变为目标矩阵最少需要几块钱。
思路
将初始矩阵变为目标矩阵等价于将目标矩阵变为初始矩阵(元素全为W).
我们用数组 m a p n , m map_{n,m} mapn,m存图,某一位为 1 1 1表示目标矩阵上该位为B, 0 0 0表示为W.特别地,边界上为 0 0 0.
定义数组 s u m n , m sum_{n,m} sumn,m, s u m i , j = m a p i , j ⊕ m a p i + 1 , j ⊕ m a p i , j + 1 ⊕ m a p i + 1 , j + 1 sum_{i,j}=map_{i,j}\oplus map_{i+1,j}\oplus map_{i,j+1}\oplus map_{i+1,j+1} sumi,j=mapi,j⊕mapi+1,j⊕mapi,j+1⊕mapi+1,j+1.
将 m a p map map所有元素变为 0 0 0等价于 s u m n , m sum_{n,m} sumn,m所有元素变为 0 0 0.
考虑四种操作对 s u m sum sum的影响.
首先,操作2,3是没有用的,可以被两次操作1代替.
为了方便,定义四元组 ( x 1 , y 1 , x 2 , y 2 ) (x_1,y_1,x_2,y_2) (x1,y1,x2,y2)表示左上角,右下角分别为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1), ( x 2 , y 2 ) (x_2,y_2) (x2,y2)的子矩阵.
若我们选择 ( 1 , 1 , x , y ) (1,1,x,y) (1,1,x,y)的矩阵翻转,仅有 s u m x , y sum_{x,y} sumx,y取反,花费一元.
若我们选择 ( x , y , n , m ) (x,y,n,m) (x,y,n,m)的矩阵反转,则 s u m x − 1 , y − 1 sum_{x-1,y-1} sumx−1,y−1, s u m x − 1 , m sum_{x-1,m} sumx−1,m, s u m n , y − 1 sum_{n,y-1} sumn,y−1, s u m n , m sum_{n,m} sumn,m取反,花费三元,改变四个格子.但是若进行两次操作4, s u m n , m sum_{n,m} sumn,m取反两次,即不变,花费了6元改变了6个格子,这样我们不如用操作1.
统计下 s u m sum sum数组中 1 1 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;
}