Step1 Problem:
给你 t 个数(a1, a2….at)至少有一个 0,要你构造 n*m 的矩阵,该矩阵的元素的值满足到 0 这个元素的位置的曼哈顿距离。曼哈顿距离:两个点的坐标差的绝对值和。
如果构造出满足条件的矩阵,输出 0 的坐标。
数据范围:
1<=t<=1e6, 0<=a[i]<=t, n*m = t.
Step2 Ideas:
我们假定 0 的位置 (x, y) 尽可能的靠近 (1, 1)。
那么距离 0 最远的距离为 (n, m),出现元素的最大值 Max = n+m-x-y.
我们 i 从 1 开始枚举,如果 i 出现的次数不是 4*i,这时候对于 (i-1) 这个元素一定得在边界。如果我们让其有限靠上边界,这时候 x 值就等于 i.
已知 Max, n, m, x,求出 y 然后判断是否满足要求即可。
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+5;
struct node
{
int u, v, step;
};
int vis[N], tvis[N];
bool solve(int x, int y, int n, int m)
{
memset(tvis, 0, sizeof(tvis));
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
int tmp = abs(x-i)+abs(y-j);
tvis[tmp]++;
if(tvis[tmp] > vis[tmp]) return 0;
}
}
return 1;
}
int main()
{
int n, num;
scanf("%d", &n);
memset(vis, 0, sizeof(vis));
int Max = 0;
for(int i = 0; i <n; i++)
{
scanf("%d", &num);
Max = max(Max, num);
vis[num]++;
}
int flag = 0, x = 0, y;
for(int i = 1; i <= n; i++)
{
if(vis[i] > i*4) {//大于一定构不成满足条件矩阵
flag = 1; break;
}
if(vis[i] == i*4) continue;
x = i; break;
}
if(flag || !x) {//如果找不到,全是 4 的倍数,一样构不成矩阵
printf("-1\n");
return 0;
}
for(int i = 1; i <= n; i++)
{
if(n%i == 0) {
y = i+n/i-x-Max;
if(solve(x, y, i, n/i)) {//知道 Max, n, m, x, y 判断所给数据是否满足。
printf("%d %d\n", i, n/i);
printf("%d %d\n", x, y);
return 0;
}
}
}
printf("-1\n");
return 0;
}