CF1968E.Cells Arrangement-构造(给个和题解不同的做法)

link:https://codeforces.com/problemset/problem/1968/E
题意:需要构造一个 \(n\times n\) 的棋盘,在上面放 \(n\) 枚棋子,设集合 \(\mathcal{H}\) 表示两两之间曼哈顿距离构成的集合,要让 \(|\mathcal{H}|\) 最大。给出放棋子的方案。


首先说说题解的做法…考虑把距离为奇数和偶数的分开想…然后就会有下面这种,对角线放一堆,然后角落放两个的操作,非常合理…

但是我完全没想到这么造…

首先想的是,距离最近是 \(0\),最远是 \(2(n-1)=2n-2\),答案上界应该是 \(2n-1\),那我们就看看能不能取到上界,想这么一个构造:如果在左上角放了一排 \(L\) 个棋,可以得到 \([0,L-1]\) 的所有距离,至多可以造到 \([0,n-1]\),这不够用

如果把棋盘分成四份,左上角放 \(n/2\) 个,右下角放一个,会发生什么呢?

右下角能额外产生最小 \(n-1+(n/2)=\frac{3}{2} n-1\),最大 \(2n-2\) 的值,这样是把 \([0,2n-2]\) 的前后都覆盖住了,中间还有大约 \(n\) 个数,再放几个球:

绿色小球和左上角能产生 \([n/2,n/2-1+n/2]=[n/2,n-1]\) 的值,而黄色小球能产生 \([n/2+n/2-1,n-1+(n/2-1)]=[n-1,\frac{3}{2}n-2]\) 的值。

所以大约用了 \(\frac{n}{2}+3\) 个球就得到了最大值…剩下的随便乱放就好。
当然,具体实现的时候wa了一发, \(n=4\) 的时候太小会出问题,其他情况都能取得到。

#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;
int main(){
    fastio;
    int tc;cin>>tc;
    while(tc--){
        int n;
        cin>>n;
        vector<pii> ans;
        int lst=n;
        if(n==4){
            ans.push_back({1,1});
            ans.push_back({1,3});
            ans.push_back({4,3});
            ans.push_back({4,4});
        }else{
            rep(i,1,(n+1)/2){
                ans.push_back({1,i});
                lst--;
            }
            ans.push_back({n,n});lst--;
            if(lst){
                ans.push_back({(n+1)/2,(n+1)/2+1});
                lst--;
            }
            if(lst){
                ans.push_back({(n+1)/2+1,n});
                lst--;
            }
            while(lst--)ans.push_back({n,n});
        }

        for(auto [x,y]:ans)cout<<x<<' '<<y<<endl;
        cout<<endl;
    }
    return 0;
}
posted @ 2024-05-03 21:55  yoshinow2001  阅读(38)  评论(0编辑  收藏  举报