Luogu3164 CQOI2014 和谐矩阵 异或高斯消元

时间:2021-10-06 08:19:55

传送门

题意:给出$N,M$,试构造一个$N \times M$的非全$0$矩阵,其中所有格子都满足:它和它上下左右四个格子的权值之和为偶数。$N , M \leq 40$


可以依据题目中的条件列出有$N \times M$的元、$N \times M$个方程的异或方程组(异或方程组就是所有位置都是$1$或$0$,最右边一列的答案需要通过异或互相消除的方程组,一般在$mod\,2$意义下产生)。

理论上元和方程组数量一致的时候每一个元都是有唯一解的,但是在有解的情况下,其中一些方程是线性相关的,这意味着消到最后,某一些行会变成全$0$(如果不是很清楚可以像$vegetable chicken$我一样打一波$3 \times 3$和$4 \times 4$的表)。我们可以把行全$0$的元(又称之为*元)全部设为$1$,因为它们是多少对方程最后有无解没有关系,然后一步步把上面推出来即可。

因为复杂度为$1600^3$平常的高斯消元速度很慢,所以可以用神仙$STL\,bitset$优化

 #include<bits/stdc++.h>
 using namespace std;

 inline int read(){
     ;
     ;
     char c = getchar();
     while(c != EOF && !isdigit(c)){
         if(c == '-')
             f = ;
         c = getchar();
     }
     while(c != EOF && isdigit(c)){
         a = (a << ) + (a << ) + (c ^ ');
         c = getchar();
     }
     return f ? -a : a;
 }

 ][] = {,,,-,,,-,,,};
 bitset <  > gauss[] , ans;

 int main(){
 #ifdef LG
     freopen("3164.in" , "r" , stdin);
     freopen("3164.out" , "w" , stdout);
 #endif
     int M , N;
     cin >> M >> N;
      ; i < M ; i++)
          ; j < N ; j++)
              ; k <  ; k++)
                 ] >=  && i + dir[k][] < M && j + dir[k][] >=  && j + dir[k][] < N)
                     gauss[i * N + j][(i + dir[k][]) * N + j + dir[k][]] = ;
     ;
      ; i < M * N ; i++){
         int j = now;
         while(j < M * N && !gauss[j][i])
             j++;
         if(j == M * N)
             continue;
         if(j != now)
             swap(gauss[now] , gauss[j]);
         while(++j < M * N)
             if(gauss[j][i])
                 gauss[j] ^= gauss[now];
         now++;
     }
      ; i >=  ; i--){
         if(!gauss[i][i])
             ans[i] = ;
         if(ans[i])
              ; j >=  ; j--)
                 if(gauss[j][i])
                     ans[j] = ans[j] ^ ;
     }
      ; i < M ; i++){
          ; j < N ; j++){
             putchar(ans[i * N + j] + );
             putchar(' ');
         }
         putchar('\n');
     }
     ;
 }