题解:CF1917E Construct Matrix

· · 题解

由于 n 是偶数,因此每一行的所有数字的按位异或结果都相同时 1 的个数一定是偶数,得出 k 为奇数时必然无解。

然后进行分讨。

当 k\equiv0\pmod 4 时

把每四个 1 看成一组,我们发现给一个 2\times 2 的全 0 子矩阵变成全 1 时,每行每列的奇偶性不变,因此只需要依次填充每个子矩阵直到 k=0 即可。

当 k\equiv 2\pmod 4 时

``` Yes 0 1 1 0 ``` 下面只考虑 $n>2$ 的情况 #### 当 $k<6$ 或 $k>n^2-6$ 时 $k<6$ 时说明 $k=2$,显然无解。 $k>n^2-6$ 时说明 $k=n^2-2$,此时我们可以先将矩阵全填成 $1$,问题转换为让 $2$ 个 $1$ 变成 $0$,显然也无解。 #### 当 $6\le k\le \dfrac{n^2}2$ 时 我们将左上角的 $4\times 4$ 的矩阵填充为下面的样子: ``` 1100 1010 0110 0000 ``` 这样会消耗 $6$ 个 $1$,而且每行每列的 $1$ 的个数都是偶数,此时就转换为了 $k\equiv 0\pmod 4$ 的问题,依次填充大小为 $2\times 2$ 的子矩阵即可(注意不要填到左上角)。 左上角的矩阵只会牺牲 $10$ 个位置不能放 $1$,而 $k\le \dfrac {n^2}2\le n^2-10$,因此这么做可以覆盖所有 $k\le \dfrac {n^2}2$ 的情况。 #### 当 $\dfrac{n^2}2<k\le n^2-6$ 时 我们将所有位置填 $1$,问题就转换为了填 $n^2-k$ 个 $0$,而 $n^2-k\le \dfrac {n^2}2$,所以可以按照 $k\le \dfrac{n^2}2$ 的情况做。 ```cpp #include<bits/stdc++.h> #define int long long #define no return cout << "No\n", 0; #define main(x) MiAn();int mIaN();main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int t=1;if(strlen(#x))cin>>t;while(t--)mIaN();}int mIaN() using namespace std; const int N = 1010; int a[N][N]; int main(1) { int n, k; cin >> n >> k; if (k & 1) no; for (int i = 1; i <= n; i++) memset(a[i], 0, sizeof(a[i])); if (k % 4 == 0) { for (int i = 1; i <= n; i += 2) { for (int j = 1; j <= n; j += 2) { if (!k) break; a[i][j] = a[i+1][j] = a[i][j+1] = a[i+1][j+1] = 1; k -= 4; } } } else { if (n == 2) { a[1][1] = a[2][2] = 1; } else { if (k < 6 || k > n*n-6) no; if (k > n*n/2) { for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { a[i][j] = 1; } } k = n*n-k; } a[1][1] ^= 1, a[1][2] ^= 1; a[2][1] ^= 1, a[2][3] ^= 1; a[3][2] ^= 1, a[3][3] ^= 1; k -= 6; for (int i = 1; i <= n; i += 2) { for (int j = 1; j <= n; j += 2) { if (i <= 3 && j <= 3) continue; if (!k) break; a[i][j] ^= 1, a[i+1][j] ^= 1; a[i][j+1] ^= 1, a[i+1][j+1] ^= 1; k -= 4; } } } } cout << "Yes\n"; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cout << a[i][j] << " "; } cout << "\n"; } return 0; } ```