题解
设矩阵是 (n) 行 (m) 列的,且唯一的值为 (0) 的点在 ((x,y))。不妨设 (xle n-x+1,yle m-y+1),因为可以通过旋转和翻转矩阵将 ((x,y)) 放到这个区域内。
于是,矩阵中离 ((x,y)) 最远的点一定是 ((n,m))。它们之间的距离是 (lvert n-x vert+lvert m-y vert=n+m-x-y)。找到给定的 (t) 个数中的 (max),设为 (alpha),则有 (alpha=n+m-x-y)。
可以发现,矩阵中值为 (a) 的数(也即和 ((x,y)) 的距离为 (a) 的位置)在不卡边界的情况下有 (4a) 个。
如下图:
图中 (1,2) 各有 (4,8) 个,而从 (3) 开始就卡了边界,因此 (3) 只有 (8) 个而不是 (12) 个。
设最小的被卡边界的数是 (v),易知 (min(x,y)=v)。不妨设 (x=v),根据上面讨论过的 (alpha=n+m-x-y),可以算出 (y)。
此时,枚举 (n imes m) 个位置,并检查其是否与给定的 (t) 个数 (a_1,a_2,dots,a_t) 相同即可。
由于需要满足 (n imes m=t),所以枚举 (t) 的约数作为 (n,m) 的值即可。
时间复杂度 (mathcal{O}(toperatorname{d}(t))),(operatorname{d}) 是约数个数函数。
代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
template<typename T> void Read(T &_x){
_x=0;int _f=1;
char ch=getchar();
while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
while(isdigit(ch)) _x=_x*10+(ch^48),ch=getchar();
_x*=_f;
}
template<typename T,typename... Args> void Read(T &_x,Args& ...others){
Read(_x);Read(others...);
}
typedef long long ll;
const int T=1e6+5;
int t,cnt[T],mx,cnt_[T];
int Abs(int x){
return x<0?-x:x;
}
int main(){
Read(t);
For(i,1,t){
int x;Read(x);
++cnt[x],mx=max(mx,x);
}
int x=0;
For(i,1,t){
if(cnt[i]!=4*i){
x=i;break;
}
}
For(n,1,t){
if(t%n) continue;
int m=t/n,y=n+m-x-mx;
if(x>n||y<=0) continue;
memset(cnt_,0,sizeof cnt);
For(i,1,n)
For(j,1,m) ++cnt_[Abs(i-x)+Abs(j-y)];
if(memcmp(cnt,cnt_,sizeof cnt)==0){
printf("%d %d
%d %d
",n,m,x,y);
return 0;
}
}
puts("-1");
return 0;
}