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 5 和 4 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;
}

浙公网安备 33010602011771号