# codeforecs1391D (#663 Div2) 505

https://codeforces.com/contest/1395/problem/D

先给出一个n, 一个m，保证n*m<= 1e6
然后给出n行m列的一个矩阵（只包含数字0和1）
先要求你更改一些位置（可以不更改）
使得改矩阵中每个变成为偶数的方形区域内数字1的个数为奇数

3 3
101
001
110


7 15
000100001010010
100111010110001
101101111100100
010000111111010
111010010100001
000011001111101
111111011010011



2


-1


1.如图1，可以证明其实min（n, m）<= 3 最终才可能有解
2.如图2，对于min（n，m）<= 3时，我们让n <= m（矩形横竖摆放答案都一样），对于枚举到第i位，

dp[i][s] = dp[i - 1][ps] + (本次花费)


ac代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1e6 + 5;

int dp[maxn][8];
char tmp[maxn];
vector<vector<bool>>vec(maxn);
int n, m;

int getTake(int ii, int st);
bool chkValid(int pst, int st);
void Min(int &xx, int yy);
void out_dp();

int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%s", tmp);
for (int j = 0; j < m; j++)
vec[i].push_back(tmp[j] - '0');
}

if (n >= 4 && m >= 4)
printf("-1\n");
else {
if (n > m)
swap(n, m);
if (n == 1) printf("0\n");
else {
int maxSt = 1 << n;

memset(dp, -1, sizeof(dp));
for (int st = 0; st < maxSt; st++)
dp[1][st] = getTake(1, st);

for (int ii = 2; ii <= m; ii++) {
for (int st = 0; st < maxSt; st++) {
int thisTake = getTake(ii, st);

for (int pst = 0; pst < maxSt; pst++) {
if (dp[ii - 1][pst] == -1) continue;
if (!chkValid(pst, st)) continue;
Min(dp[ii][st], dp[ii - 1][pst] + thisTake);
//printf("dp[%d][%d] from pst=%d get:%d\n", ii, st, pst, dp[ii][st]);
}
}
}
int res = -1;

for (int st = 0; st < maxSt; st++) Min(res, dp[m][st]);
printf("%d\n", res);

//out_dp();
}
}
return 0;
}

int getTake(int ii, int st)
{
int res = 0;

for (int i = 1; i <= n; st >>= 1, i++)
if ((st & 1) != vec[i][ii - 1])
res++;

return res;
}

int get1(int xx)
{
int res = 0;

while (xx) {
res += xx & 1;
xx >>= 1;
}
return res;
}

bool chkValid(int pst, int st)
{
for (int i = 2, j = 3; i <= n; i++, j <<= 1) {
int pthis2 = pst & j;
int this2 = st & j;

if (!((get1(pthis2) + get1(this2)) & 1)) return 0;
}
return 1;
}

void Min(int & xx, int yy)
{
if (xx == -1 || yy < xx)
xx = yy;
}

void out_dp()
{
int maxSt = 1 << n;

for (int i = 1; i <= m; i++)
for (int st = 0; st < maxSt; st++)
printf("dp[%d][%d]=%d\n", i, st, dp[i][st]);
}

09-19 1万+

01-26 11万+
05-22 12万+
04-11 8182
05-18 3万+
12-26 6039
12-29 6902
06-19 8187
09-25 1万+