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;
}
posted @ 2024-04-09 17:13  yoshinow2001  阅读(3)  评论(0编辑  收藏  举报