洛谷 NOIP 2023 模拟赛-汪了个汪-题解

简要题意

棋盘上有 n n n 行,第 i i i 行有 i i i 个格子。你要在格子填 1 ∼ n 1\sim n 1n,满足:

  • 每行第一个数互不相同
  • 所有在行上相邻的两个数所组成的无序对互不相同
  • 每行的数互不相同

n ≤ 4000 n\le4000 n4000

题解

容易发现棋盘上的无序对与总的无序对数量是相同的,也就是说,要全部填满。可以考虑把它们分类,然后再按规律放数。

我们发现,无序对中两数差为 1 1 1 n − 1 n-1 n1 个,差为 2 2 2 n − 2 n-2 n2 个, … \dots ,差为 n − 1 n-1 n1 1 1 1 个,看上去很巧,如果能把它们按行归类,就好了。但是显然 2 , 5 , 3 , 6 , … 2,5,3,6,\dots 2,5,3,6, 是放不进的。

考虑能否这样,第 i i i 行有差为 1 ∼ i − 1 1\sim i-1 1i1 的无序对各 1 1 1 个。发现如果这样构造: x , x + 1 , x − 1 , x + 2 , x 2 , … x,x+1,x-1,x+2,x_2,\dots x,x+1,x1,x+2,x2,,是符合条件的。于是就做完了。

#include
using namespace std;
int n,t;
vector<int> v[4001];
bool cmp(vector<int> v1,vector<int> v2)
{
    return v1.size()<v2.size();
}
int main()
{
    cin>>n>>t;
    for(int i=1;i<=n;i++){
        int x=0,now=i,y=1;
        while(now>0&&now<=n){
            v[i].push_back(now);
            now=now+(x&1?1:-1)*y;
            y++;
            x++;
        }
    }
    sort(v+1,v+1+n,cmp);
    for(int i=1;i<=n;i++){
        for(auto j:v[i]){
            printf("%d ",j);
        }
        puts("");
    }
}

你可能感兴趣的:(算法)