题解:CF1917E Construct Matrix
CYFqwq
·
·
题解
由于 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;
}
```