Description
给定一个 (n imes m) 的 (01) 矩阵,每次操作可以将某个 (2 imes2) 的矩阵内的 (3) 个数取反,请在 (n imes m) 步内将矩阵变为全 (0)。
Solution
我们的基本思路是,任何一个 (2 imes 2) 的矩阵都可以经过不超过 (4) 次操作消去得到目标状态,因此对于任何一个边长为偶数的矩阵,我们只需要对于每个 (2 imes 2) 的小方块执行一次操作即可;对于一个边长为奇数的矩阵,我们先把它的最后一行(列)暴力消去,然后转化为偶数的情况进行处理。
对于一个 (2 imes 2) 的方块的不超过四步操作,并且显然操作最多只会有 (4) 种,每种要么进行 (0) 次,要么进行 (1) 次,因此总共只有 (16) 种可能,暴力枚举这些可能即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
vector<pair<int, int>> s[2][2][2][2];
bool check(int a00, int a01, int a10, int a11, int b00, int b01, int b10, int b11)
{
for (int i = 0; i < b00 + b01 + b10 + b11; i++)
{
a00 ^= 1;
a01 ^= 1;
a10 ^= 1;
a11 ^= 1;
}
return ((a00 ^ b00) | (a01 ^ b01) | (a10 ^ b10) | (a11 ^ b11)) == 0;
}
void presolve(int a00, int a01, int a10, int a11)
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
for (int l = 0; l < 2; l++)
{
if (check(a00, a01, a10, a11, i, j, k, l))
{
if (i)
s[a00][a01][a10][a11].push_back({0, 1}),
s[a00][a01][a10][a11].push_back({1, 1}),
s[a00][a01][a10][a11].push_back({1, 0});
if (j)
s[a00][a01][a10][a11].push_back({0, 0}),
s[a00][a01][a10][a11].push_back({1, 0}),
s[a00][a01][a10][a11].push_back({1, 1});
if (k)
s[a00][a01][a10][a11].push_back({0, 1}),
s[a00][a01][a10][a11].push_back({0, 0}),
s[a00][a01][a10][a11].push_back({1, 1});
if (l)
s[a00][a01][a10][a11].push_back({0, 0}),
s[a00][a01][a10][a11].push_back({0, 1}),
s[a00][a01][a10][a11].push_back({1, 0});
}
}
}
}
}
}
void presolve()
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 2; k++)
{
for (int l = 0; l < 2; l++)
{
presolve(i, j, k, l);
}
}
}
}
}
vector<pair<int, int>> solve(int i, int j, vector<vector<int>> &a)
{
auto ans = s[a[i][j]][a[i][j + 1]][a[i + 1][j]][a[i + 1][j + 1]];
for (auto &t : ans)
{
t.first += i;
t.second += j;
}
return ans;
}
vector<pair<int, int>> bruteforce(int i, int j, vector<vector<int>> &a, int n, int m)
{
vector<pair<int, int>> ans;
if (a[i][j])
{
if (i < n && j < m)
{
ans.push_back({0, 0});
ans.push_back({0, 1});
ans.push_back({1, 0});
}
else if (i < n)
{
ans.push_back({0, 0});
ans.push_back({1, 0});
ans.push_back({1, -1});
}
else
{
ans.push_back({0, 0});
ans.push_back({0, 1});
ans.push_back({-1, 1});
}
}
for (auto &t : ans)
{
t.first += i;
t.second += j;
}
for (auto t : ans)
{
a[t.first][t.second] ^= 1;
}
return ans;
}
void LinkToEnd(vector<pair<int, int>> &ans, vector<pair<int, int>> tmp)
{
ans.insert(ans.end(), tmp.begin(), tmp.end());
}
void solve()
{
int n, m;
cin >> n >> m;
vector<vector<int>> a(n + 2);
for (int i = 1; i <= n; i++)
{
a[i].resize(m + 2);
}
for (int i = 1; i <= n; i++)
{
string tmp;
cin >> tmp;
for (int j = 1; j <= m; j++)
{
a[i][j] = tmp[j - 1] - '0';
}
}
vector<pair<int, int>> ans;
if (n & 1)
{
for (int j = 1; j <= m; j++)
{
LinkToEnd(ans, bruteforce(1, j, a, n, m));
}
}
if (m & 1)
{
for (int i = 1; i <= n; i++)
{
LinkToEnd(ans, bruteforce(i, 1, a, n, m));
}
}
for (int i = 1 + (n & 1); i <= n; i += 2)
{
for (int j = 1 + (m & 1); j <= m; j += 2)
{
LinkToEnd(ans, solve(i, j, a));
}
}
int result = ans.size() / 3;
cout << result << endl;
for (int i = 0; i < result; i++)
{
for (int j = 0; j < 3; j++)
{
cout << ans[3 * i + j].first << " " << ans[3 * i + j].second << " ";
}
cout << endl;
}
}
signed main()
{
presolve();
// for(int i=0;i<2;i++)
// {
// for(int j=0;j<2;j++)
// {
// for(int k=0;k<2;k++)
// {
// for(int l=0;l<2;l++)
// {
// auto& x=s[i][j][k][l];
// for(auto p:x)
// {
// cout<<p.first<<","<<p.second<<" ";
// }
// cout<<endl;
// }
// }
// }
// }
int t;
cin >> t;
while (t--)
{
solve();
}
}