CF1917E-构造
link:https://codeforces.com/contest/1917/problem/E
给定 \(n,k\),保证 \(n\) 是偶数,需要构造一个 \(n\times n\) 的01矩阵,满足一共有 \(k\) 个1,且每行每列1的个数的奇偶性相同。给出构造或断定不存在方案。
\(n\) 是偶数意味着 \(k\) 必然是偶数(不管每行是奇还是偶数个1,最终总和必然是偶数)
因此首先排除 \(k\) 奇数的情况。
\(k\) 是偶数时,想一个很美妙的事情,放一个 \(2\times 2\) 的全 \(1\) 的格子总是可以保持奇偶性不变的,而 \(n\) 又是偶数,因此如果 \(k\bmod 4=0\) 我们也做完了。
然后考虑 \(k\bmod 4=2\) ,\(k=2\) 无解(对于corner case可以枚举几种可能的情况判断确实无解),\(k=n^2-2\) 是对称的也是无解,否则 \(k=6\) 是能构造出来的(此时意味着 \(n\) 至少是 \(4\)):
1 | 1 | 0 | 0 |
---|---|---|---|
1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 |
0 | 0 | 0 | 0 |
而 \(k=10\) 和 \(k=6\) 又是对称的,\(k=14\) 对于 \(4\times 4\) 的情形来说和 \(k=2\) 别无二致,是无解的。
因此到这里可以确定做法了:
- k是奇数无解
- k是2或 \(n^2-2\) 无解
- 否则,如果 \(k\bmod 4=2\),判断 \(k\bmod 16\) 的结果,如果是 \(6\) 则按照上面的方式构造一个,否则如果是 \(2,10,14\) 的话:若 \(k\bmod 16=2\),但 \(k\neq 2\),所以 \(k\) 至少是 \(18\),可以先减掉 \(10\) 个,对 \(10,14\) 同理,此时可以先按照 \(k=10\) 的 \(4\times 4\) 的矩阵构造一个10个1的部分。
- 剩下的情况, \(k\bmod 4=0\),全部按照 \(2\times 2\) 的填1来构造即可。实现的时候注意到上面 \(4\times 4\) 的构造方案中,四个 \(2\times 2\) 小格子都必然至少有一个数字,因此可以用这种方式来判断,简化代码实现。
// LUOGU_RID: 154445332
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
const int N=1005;
int n,k,a[N][N];
bool work(){
cin>>n>>k;
rep(i,1,n)rep(j,1,n)a[i][j]=0;
if(k&1)return false;
else{
if(k==2||k==n*n-2){
if(n==2){
a[1][1]=a[2][2]=1;
return true;
}else return false;
}else{
if(k%4==2){
int x=n-3,y=n-3;
if(k%16==6){
a[x][y]=a[x+1][y]=a[x][y+1]=a[x+1][y+2]=a[x+2][y+1]=a[x+2][y+2]=1;
k-=6;
}else{
rep(i,x,x+3)rep(j,y,y+3)a[i][j]=1;
a[x][y]=a[x+1][y]=a[x][y+1]=a[x+1][y+2]=a[x+2][y+1]=a[x+2][y+2]=0;
k-=10;
}
}
for(int i=1;i<=n&&k;i+=2)for(int j=1;j<=n&&k;j+=2){
bool ok=true;
rep(x,0,1)rep(y,0,1)if(a[i+x][j+y])ok=false;
if(!ok)continue;
rep(x,0,1)rep(y,0,1)a[i+x][j+y]=1;
k-=4;
}
}
}
return true;
}
int main(){
fastio;
int tc;cin>>tc;
while(tc--){
if(!work())cout<<"No"<<endl;
else{
cout<<"Yes"<<endl;
rep(i,1,n){
rep(j,1,n)cout<<a[i][j]<<' ';
cout<<endl;
}
}
}
return 0;
}