W
e
l
c
o
m
e
: )

P9837 题解

奇怪的构造方法居然过了...

本构造方法暂无证明,只是提供一种乱搞做法。

对于奇数的情况

首先我们从样例入手(为 \(5\) 的情况):

1
2 3
4 2 5
3 5 1 4
5 4 3 1 2

然后我们对样例进行一点改造:

1
2 3
4 1 5
3 5 2 4
5 4 3 1 2

我们将这个数组水平翻转一下,再顺时针旋转 45 度:

        5
      3   4
    4   5   3
  2   1   2   1
1   3   5   4   2

然后就使用瞪眼法,发现偶数行和奇数行规律不同,将它们分离成两部分:

    5
  4 5 3
1 3 5 4 2

  3 4
2 1 2 1

我们发现奇数行的最后一行是 1 3 5 4 2 ,按照奇偶再分成两部分:1 3 54 2

然后我们发现最后一行先是 \(1\)\(n\) 的奇数,再是 \(n-1\)\(2\) 的偶数。

然后我们再看倒数第二行 4 5 3 和最后一行去除头尾元素的部分 3 5 4

发现倒数第二行只是把最后一行去除头尾元素的部分翻转了。

然后依照该规律向上构造即可。


再看偶行,由下到上就是从小到大的相邻的两个数反复出现而已。

从上到下先是奇数开头,再是偶数开头。

对于偶数的情况

偶数的样例只能自己手搓一个(为 \(6\) 的情况):

1
2 3
4 1 5
3 6 2 5
5 4 6 1 3
6 5 3 4 2 1

和奇数一样,将这个数组水平翻转一下,再顺时针旋转 45 度:

          6
        5   5
      3   4   3
    4   6   6   4
  2   1   2   1   2
1   3   5   5   3   1

然后将奇偶行分离:

    6
  3 4 3
2 1 2 1 2

    5 5
  4 6 6 4
1 3 5 5 3 1

奇数行和另一种情况的偶数行构造一致。

只是从上到下先是偶数开头,再是奇数开头。


不难发现偶数行是对称的。

最后一行的前半部分是 1 3 5 ,倒数第二行的前半部分是 4 6

然后我们发现最后一行是 \(1\)\(n-1\) 的奇数,倒数第二行是 \(2\)\(n\) 的偶数。

两组数据交替出现。

每次向上构造时删除头尾元素即可。

Code

#include<bits/stdc++.h>
using namespace std;
#define maxn 4003

int mp[maxn][maxn];
int ls[maxn];
int ls1[maxn], ls2[maxn];

void solve1(int n)
{
    for(int i=1;i<=n;i++) ls[i]=(i<=(n>>1)+1)?(i<<1)-1:(n-i+1)<<1;
    int cnt1=0;
    for(int i=1;i<=n;i++)
    {
        if(i&1)
        {  
            cnt1++;
            int mf=cnt1;
            if(i&2) for(int j=i;j<=n;j++)
                mp[n-j+i][n-j+1]=ls[mf++];
            else for(int j=i;j<=n;j++)
                mp[j][j-i+1]=ls[mf++];
        }
        else
        {
            if(i&2) 
            {
                int st=i-2;
                for(int j=i;j<=n;j++)
                    mp[j][j-i+1]=(st^=1)+1;
            }
            else 
            {
                int st=i-1;
                for(int j=i;j<=n;j++)
                    mp[j][j-i+1]=(st^=1)+1;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
            cout<<mp[i][j]<<' ';
        cout<<'\n';
    }
}

void solve2(int n)
{
    for(int i=1;i<=n>>1;i++) ls1[i]=(i<<1)-1;
    for(int i=1;i<=n>>1;i++) ls2[i]=(i<<1);
    for(int i=(n>>1)+1;i<=n;i++) ls1[i]=((n-i+1)<<1)-1;
    for(int i=(n>>1)+1;i<=n;i++) ls2[i]=((n-i+1)<<1);
    int cnt1=0;
    for(int i=1;i<=n;i++)
    {
        if(i&1)
        {  
            cnt1++;
            int mf=cnt1;
            if(i&2) for(int j=i;j<=n;++j)
                mp[n-j+i][n-j+1]=ls2[mf++];
            else for(int j=i;j<=n;++j)
                mp[j][j-i+1]=ls1[mf++];
        }
        else
        {
            if(i&2) 
            {
                int st=i-2;
                for(int j=i;j<=n;++j)
                    mp[j][j-i+1]=(st^=1)+1;
            }
            else 
            {
                int st=i-1;
                for(int j=i;j<=n;++j)
                    mp[j][j-i+1]=(st^=1)+1;
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
            cout<<mp[i][j]<<' ';
        cout<<'\n';
    }
}


int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int n,w;
    cin>>n>>w;
    if(n&1) return solve1(n), 0;
    else return solve2(n), 0;
}
posted @ 2024-08-25 20:54  Jimmy-LEEE  阅读(29)  评论(0)    收藏  举报