题目:点击打开链接
题意:给你t个数字,要你组成一个n x m的矩阵,这个矩阵满足这样的条件 ①矩阵里面的元素到“0”这个元素的曼哈顿距离为元素值大小。曼哈顿距离:两个点坐标差的绝对值之和。现在问你的是输出n,m以及元素“0”的坐标(x,y);如果不存在这样的矩阵,输出“-1”。
题意:给你t个数字,要你组成一个n x m的矩阵,这个矩阵满足这样的条件 ①矩阵里面的元素到“0”这个元素的曼哈顿距离为元素值大小。曼哈顿距离:两个点坐标差的绝对值之和。现在问你的是输出n,m以及元素“0”的坐标(x,y);如果不存在这样的矩阵,输出“-1”。
分析:
由于这个东西具有对称性,每一种解都可以通过翻转将它变化出最多四种解。
我们仅考虑(x,y)(x,y)在靠近左边界或者上边界的解。
举个例子,题目中给出了这种情形:
那么我们可以等价为:
我们可以假设值为0的点在左上角(x,y),距离点(n,m)最远,可以得出方程n-x+m-y=b(给出的数中的最大值),变形得y=n-x+m-b,n和m很好求,都是t的因子,x为i当ct[i]!=4*i的最小值,因为看图可以得出规律第i(i>0)层数字为i+1的数量为4*i,不满足说明最先出界,也就是值为0的点的x坐标,然后依次枚举根号t以内的因子判断是否满足条件就行了,复杂度为O(sqrt(t)*t),差不多10^9了,codeforces评测机真是快啊。
代码:
#pragma comment(linker, "/STACK:102400000,102400000")///手动扩栈
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
using namespace std;
#define debug test
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
#define eps 1e-10
#define MOD 1000000007
#define PI acos(-1.0)
const int N = 1e6+10;
ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
int to[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int t,x,y,n,m,ct[N],tp[N];
int main() {
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>t;
int nm,mx=0;
for(int i=0;i<t;i++) {
cin>>nm;
ct[nm]++;
mx=max(mx,nm);
}
for(int i=1;i<=t;i++)
if(ct[i]!=4*i) {
x=i;break;
}
int flag=1;
for(int i=1;i*i<=t;i++) {
if(t%i==0) {
n=i,m=t/i,y=n-x+m-mx;
mst(tp,0);
for(int j=1;j<=n;j++)
for(int k=1;k<=m;k++)
tp[(int)abs(j-x)+(int)abs(k-y)]++;
int fg=0;
for(int i=0;i<t;i++) if(ct[i]!=tp[i]) fg=1;
if(fg==0) {
cout<<n<<" "<<m<<endl;
cout<<x<<" "<<y<<endl;
flag=0;
break;
}
}
}
if(flag) cout<<-1<<endl;
return 0;
}
参考博客:https://blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/80951796