3503: [Cqoi2014]和谐矩阵
分析:
对于每个点,可以列出一个方程a[i][j]=a[i][j-1]^a[i][j+1]^a[i-1][j]^a[i+1][j],于是可以列出n*m个方程,高斯消元,复杂度$O(n^3m^3)$。可以再bitset优化一下。
还有一种复杂度更优的做法:如果知道了第一行,那么整个矩阵都可以推出来了,即每个点可以有第一行的几个位置异或得到。
所以可以推出每一行每个点,与第一行的那些点有关系,推得时候转化以下上面的式子,使得每一个点只与上面的行有关系。
由于第n+1行只能全部是0,所以可以推出第n+1行每个点与第一行每个点的关系,然后列出m个方程,高斯消元,复杂度$O(m^3)$。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 55; LL a[N][N], b[N][N], c[N][N]; int n, m; void Gauss() { for (int k = 1; k <= m; ++k) { int r = k; while (r <= m && !a[r][k]) r ++; if (r > m) continue; if (r != k) for (int j = 1; j <= m; ++j) swap(a[k][j], a[r][j]); for (int i = k + 1; i <= m; ++i) if (a[i][k]) for (int j = 1; j <= m; ++j) a[i][j] ^= a[k][j]; } for (int i = m; i; --i) { if (!a[i][i]) { c[1][i] = 1; continue; } c[1][i] = a[i][m + 1]; for (int j = i + 1; j <= m; ++j) if (a[i][j]) c[1][i] ^= c[1][j]; } } int main() { n = read(), m = read(); for (int i = 1; i <= m; ++i) b[1][i] = (1ll << (i - 1)); for (int i = 2; i <= n + 1; ++i) for (int j = 1; j <= m; ++j) b[i][j] = b[i - 1][j - 1] ^ b[i - 1][j] ^ b[i - 1][j + 1] ^ b[i - 2][j]; for (int i = 1; i <= m; ++i) for (int j = 1; j <= m; ++j) a[i][j] = (b[n + 1][i] >> (j - 1)) & 1; Gauss(); for (int i = 2; i <= n; ++i) for (int j = 1; j <= m; ++j) c[i][j] = c[i - 1][j - 1] ^ c[i - 1][j] ^ c[i - 1][j + 1] ^ c[i - 2][j]; for (int i = 1; i <= n; ++i, puts("")) for (int j = 1; j <= m; ++j) printf("%lld ", c[i][j]); return 0; }