题意:给出一种矩阵,有且只有一个位置是0,其余位置的值是与0的曼哈顿距离。现给你t个数,问这t个数是否能构成一个上述矩阵,若可以,输出矩阵的大小以及0的位置。
分析:由于矩阵是由大小n*m,0的位置(x,y)确定,只要有了这4个参数我们就可以求出除0位置以外的所有的值 。
我们令0在上半个矩阵,(在下半个也是一样的,可以对称过去)
再我们根据这个矩阵里面,当矩阵无限大,每个数的个数就是值*4,(1出现4次,2出现8次,3出现12次…) 可以知道从1开始枚举,最先缺少的数就是0的x坐标。
然后我们枚举t的因子作为n,m的值,利用 n-x+m-y==mmax (mmax为离0位置最远的曼哈顿距离) 求出y=n-x+m-mmax
于是n m x y全都有了 ,再求出其他位置的值的个数情况与题目比较即可。
时间复杂度O(sqrt(t)*t) 大概1e9 cf的机子跑200ms左右orz
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6+5;
const int mx = 40;
const int mod = 1e9+5;
const ll inf = 34359738370;
const int INF = 1e9+5;
int c[maxn];//每个数出现的次数
int t,n,m,x=1,y,maxx;//0的位置 (x,y) x为最先缺少的数 y=n-x+m-mmax
int c1[maxn];//用于验证的时候和c对比
int dis(int a,int b)
{
return abs(a-x)+abs(b-y);
}
bool check()
{
for(int k=0;k<t;k++)
{
if(c[k] != c1[k])
{
return 0;
}
}
return 1;
}
int main()
{
bool ok=0;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
int a;
scanf("%d",&a);
++c[a];
maxx=max(maxx,a);
}
for(int i=1;i<=t;i++)
{
if(c[i] != i*4) //最先开始缺少的数
{
x=i;
break;
}
}
for(int i=1;i<=t;i++)//枚举t的因子 n*m==t
{
if(t%i) continue;
n=i,m=t/i;
y=n-x+m-maxx;
if(x < 1 || x > n || y < 1 || y > m) continue;
memset(c1,0,sizeof(c1));
for(int k=1;k<=n;k++)
{
for(int l=1;l<=m;l++)
{
++c1[dis(k,l)];
}
}
if(check())
{
printf("%d %d\n%d %d\n",n,m,x,y);
ok=1;
break;
}
}
if(!ok) puts("-1");
return 0;
}