CF1118C Palindromic Matrix

思路

因为回文矩阵左右翻转和上下翻转都不变,所以可以知道回文矩阵一定满足 \(a_{i,j}=a_{n-i+1,j}=a_{i,n-j+1}=a_{n-i+1,n-j+1}\)

由于当 \(n\) 为奇数,\(x=\frac{n+1}{2}\) 时,\(x=n-x+1\),所以需要根据 \(n\) 的奇偶性分类讨论。

  • \(n\) 为偶数时

此时不存在 \(x\) 满足 \(x=n-x+1\),所以所有数字的个数一定为 \(4\) 的倍数,直接枚举位置填充即可。

  • \(n\) 为奇数时

\(i=\frac{n+1}{2}\)\(i=n-i+1\),则只需满足 \(a_{i,j}=a_{i,n-j+1}\),此时该数字只要满足为 \(2\) 的倍数即可填充,\(j\) 同理。

特别的,当 \(i=\frac{n+1}{2}\)\(j=\frac{n+1}{2}\) 时,该数字无需满足任何条件即可填充。

对于无解的情况,只需在填入时判断即可。

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n,a[405],b[25][25];
vector<int> num;
unordered_map<int,int> cnt;
void nxt(int &nx,int &ny){
	if(nx==n/2)
		nx=1,ny++;
	else
		nx++;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n;
	for(int i=1;i<=n*n;i++){
		cin>>a[i];
		if(!cnt[a[i]])
			num.push_back(a[i]);
		cnt[a[i]]++;
	}
	int nx=1,ny=1,zx=1,zy=1;
	bool odd=1;
	for(int v:num){
		if(cnt[v]%4!=0&&n%2==0){
			cout<<"NO";
			return 0;
		}
		if(n%2==1){
			if(cnt[v]%2==1){
				if(odd)
					odd=0,b[n/2+1][n/2+1]=v,cnt[v]--;
				else{
					cout<<"NO";
					return 0;
				}
			}
			if(cnt[v]%4==2){
				if(zx<=n/2)
					b[zx][n/2+1]=v,b[n-zx+1][n/2+1]=v,zx++,cnt[v]-=2;
				else if(zy<=n/2)
					b[n/2+1][zy]=v,b[n/2+1][n-zy+1]=v,zy++,cnt[v]-=2;
				else{
					cout<<"NO";
					return 0;
				}
			}
		}
		while(cnt[v]&&ny<=n/2){
			b[nx][ny]=v;
			b[nx][n-ny+1]=v;
			b[n-nx+1][ny]=v;
			b[n-nx+1][n-ny+1]=v;
			nxt(nx,ny);
			cnt[v]-=4;
		}
	}
	for(int v:num){
		while(cnt[v]){
			if(zx<=n/2)
				b[zx][n/2+1]=v,b[n-zx+1][n/2+1]=v,zx++,cnt[v]-=2;
			else if(zy<=n/2)
				b[n/2+1][zy]=v,b[n/2+1][n-zy+1]=v,zy++,cnt[v]-=2;
			else{
				cout<<"NO";
				return 0;
			}
		}
	}
	cout<<"YES"<<endl;
	for(int i=1;i<=n;i++,cout<<endl)
		for(int j=1;j<=n;j++)
			cout<<b[i][j]<<" ";
	return 0; 
}
posted @ 2025-03-26 11:01  WuMin4  阅读(20)  评论(0)    收藏  举报