link
AT4512 [AGC030C] Coloring Torus
给出一个数字 \(K(≤1000)\)
要求构造出一个 \(n(≤500)\)行 \(n\) 列的矩阵
满足:
-
\(∀i,j∈[1,n],A[i,j]∈[1,K]\)
-
\(∀v∈[1,K],∃i,j∈[1,n],A[i,j]=v\)
-
定义\(cnt_{i,j,v}\)表示周围 \(4\) 个格子数字等于 \(v\) 的个数,\(∀v∈[1,K]\) 若 \(A[i][j]=A[i'][j']\) 则要求 \(cnt_{i,j,v}=cnt_{i',j',v}\)
sol
通过样例,我们可以得出 \(n≤500\) 时的构造方法
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
然后考虑怎么将 \(K\) 扩大到 \(1000\)
考虑一行的数等价性,然后再考虑题目给的循环是什么意思,就是在给定的空间里构造出尽可能多的行!
于是我们想到了对角线构造
1 2 3 4 5
6 1 2 3 4
7 6 1 2 3
8 7 6 1 2
9 8 7 6 1
现在就能构造出 \(2n-1\) 的 \(K\) 了
但如果 \(K\)是偶数了,考虑对上面方法进行改造
发现一个斜线上的数是等价的,所以把一个斜线上交错放上一些多余的数是不影响答案的
就变成了这样
1 2 3 4 5
6 10 2 3 4
7 6 1 2 3
8 7 6 10 2
9 8 7 6 1
就可以将偶数的情况构造出来了
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=505;
int K;
int nx[maxn];
int mp[maxn][maxn];
int main(){
freopen("AT4512.in","r",stdin);
freopen("AT4512.out","w",stdout);
scanf("%d",&K);
if(K<=500){
printf("%d\n",K);
for(int i=1;i<=K;i++){
for(int j=1;j<=K;j++)
printf("%d ",i);
printf("\n");
}
}else {
int n=500,N=0;
for(int i=1;i<=n;i++)nx[i]=i+1;
nx[n]=1,printf("%d\n",n);K-=n;
for(int i=1;i<=n;i++){
int a=++N,b=K?++N:N;
K-=b-a;
for(int x=1,y=i;x<=n;x++,y=nx[y])
mp[x][y]=x&1?a:b;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
printf("%d ",mp[i][j]);
printf("\n");
}
}
return 0;
}