试题描述
There are N× Ncards, which form an N× Nmatrix. The cards can be placed upwards or downwards. Now Acer is going to do some operations so that all the cards are placed upwards after the operations. In each operation, Acer can flip over exactly an M× Msub-matrix of cards. Acer wants to know the minimum number of operations to achieve his goal.
输入
The first line contains two integers, N and M (0 < M ≤ N ≤ 1000).
Each of the next N lines contains N integers. If the integer is 1, the corresponding card is placed upwards initially; otherwise it is placed downwards initially.
输出
Output an integer, which indicate the minimum number of operations. If there is no solution, output -1.
输入示例
4 2 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0
输出示例
5
数据规模及约定
见“输入”
题解
贪心,我们发现进行两次完全相同的操作是没有必要的,并且操作的先后顺序无所谓,所以我们就从上到下从左到右依次进行反转操作。当 (i, j) 这个格子是 0,则反转 (i, j) 为左上角,(i+m-1, j+m-1) 为右下角的矩形,如果这个矩形超界,就说明不可能全部翻成正面。
每次直接暴力反转是不行的,可以打一个 flip[i][j] 标记,然后查看左上角总共打了多少次标记,记这个次数为 x,那么 x 为奇数时表明这个格子与最初的状态相反,x 为偶数时说明这个格子和最初状态相同,这个标记是动态加的,所以要用数据结构维护,不难发现这是个二维偏序,我们的操作已经将它的一维排好序了,只需要在第二维建立一个树状数组就行了。
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if(Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); } return x * f; } #define maxn 1010 int n, m; bool A[maxn][maxn], flip[maxn][maxn]; int C[maxn]; void add(int x, int v) { for(; x <= n; x += x & -x) C[x] += v; return ; } int sum(int x) { int res = 0; for(; x; x -= x & -x) res += C[x]; return res; } int main() { n = read(); m = read(); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) A[i][j] = read(); int cnt = 0; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) { add(j, flip[i][j]); A[i][j] ^= (sum(j) & 1); if(A[i][j]) continue; if(i > n - m + 1 || j > n - m + 1) return puts("-1"), 0; // printf("%d %d\n", i, j); cnt++; A[i][j] ^= 1; flip[i][j] ^= 1; flip[i+m][j] ^= 1; flip[i][j+m] ^= 1; flip[i+m][j+m] ^= 1; add(j, 1); } printf("%d\n", cnt); return 0; }