题解P3164 [CQOI2014]和谐矩阵

很明显是一道高斯消元解线性异或方程组。

对于一个 \(n\times m\) 的矩阵,我们给每个点编一个号,

对于第 \(i\)行,第 \(j\) 列的点,则有 \(p=(i-1)\times m+j\)

那么与它相邻的点的编号就出来了,

分别是 \(p_1=p-m,p_2=p+m,p_3=p-1,p_4=p+1\)

那么对于每一个点,我们都可以列出一个方程式

\[x_p\oplus x_{p_1}\oplus x_{p_2}\oplus x_{p_3}\oplus x_{p_4}=0 \]

那么 \(n\times m\) 的矩阵就一共有 \(nm\) 个点,即我们需要列出一个 \(nm\) 元一次方程式组,

那这个方程组求出来的解就一定是答案吗?

不是,很明显,矩阵全部都为0也是这个方程组的一组合法解,

但题目又说了不能全为0,并且保证有解,那么就说明这个方程组并不是唯一解,

所以在跑完高斯消元后,对于那些自由元,我们全部赋值为1,这样就能求出答案了。

还有一个问题,这样做的时间复杂度是 \(O((nm)^3)\) 的,

所以需要用bitset优化一下,就可以 \(O(\frac{(nm)^3}{32})\) 过了

不过似乎优化了还要慢一些

代码

#include<iostream>
#include<cstdio>
#include<bitset>
using namespace std;

bitset<2005> a[2005];
int n, x, y;

void gauss()
{
    for (int r = 1, l = 1; l <= n; l++)
    {
        int t = r;
        for (int i = r; i <= n; i++)
            if (a[i][l])
                t = i;
        if (!a[t][l])
            continue;
        swap(a[t], a[r]);
        for (int i = r + 1; i <= n; i++)
            if (a[i][l])
                    a[i] = a[i] ^ a[r];
        r++;
    }
    for (int i = n; i >= 1; i--)
    {
        if (!a[i][i])
            a[i][n + 1] = 1;
        else
            for (int j = i + 1; j <= n; j++)
                a[i][n + 1] = a[i][n + 1] ^ (a[i][j] & a[j][n + 1]);
    }
}

int main()
{
    scanf("%d%d", &x, &y);
    n = x * y;
    for (int i = 1; i <= x; i++)
    {
        for (int j = 1; j <= y; j++)
        {
            int p = (i - 1) * y + j;
            int p1 = p - y, p2 = p + y, p3 = p - 1, p4 = p + 1;
            if (i > 1) a[p][p1] = 1;
            if (j > 1) a[p][p3] = 1;
            if (i < x) a[p][p2] = 1;
            if (j < y) a[p][p4] = 1;
            a[p][p] = 1;
        }
    }
    gauss();
    for (int i = 1; i <= n; i++)
    {
        printf("%d ", (a[i][n + 1] ? 1 : 0));
        if (i % y == 0)
            printf("\n");
    }
    return 0;
}
posted @ 2021-05-06 22:10  DSHUAIB  阅读(78)  评论(0编辑  收藏  举报