题目链接:
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位,
我们可以,枚举第i为的状态(s),再枚举第i-1位的状态为(ps),(n很小s最多8种,ps也是)
然后保证红框内的1的个数都为奇数个。便可以使得dp[i][s] 从dp[i-1][ps]更新过来。
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]);
}