Description

给定一个 \(n\times m\)\(01\) 矩阵,每次操作可以将某个 \(2\times2\) 的矩阵内的 \(3\) 个数取反,请在 \(n\times m\) 步内将矩阵变为全 \(0\)

Solution

我们的基本思路是,任何一个 \(2 \times 2\) 的矩阵都可以经过不超过 \(4\) 次操作消去得到目标状态,因此对于任何一个边长为偶数的矩阵,我们只需要对于每个 \(2 \times 2\) 的小方块执行一次操作即可;对于一个边长为奇数的矩阵,我们先把它的最后一行(列)暴力消去,然后转化为偶数的情况进行处理。

对于一个 \(2 \times 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();
    }
}

相关文章: