Loading

CF1004D Sonya and Matrix - 构造

题解

设矩阵是 \(n\)\(m\) 列的,且唯一的值为 \(0\) 的点在 \((x,y)\)。不妨设 \(x\le n-x+1,y\le m-y+1\),因为可以通过旋转和翻转矩阵将 \((x,y)\) 放到这个区域内。

于是,矩阵中离 \((x,y)\) 最远的点一定是 \((n,m)\)。它们之间的距离是 \(\lvert n-x\rvert+\lvert m-y\rvert=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\times m\) 个位置,并检查其是否与给定的 \(t\) 个数 \(a_1,a_2,\dots,a_t\) 相同即可。

由于需要满足 \(n\times m=t\),所以枚举 \(t\) 的约数作为 \(n,m\) 的值即可。

时间复杂度 \(\mathcal{O}(t\operatorname{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\n%d %d\n",n,m,x,y);
			return 0;
		}
	}
	puts("-1");
	return 0;
}
posted @ 2021-10-09 16:12  Alan_Zhao_2007  阅读(44)  评论(0编辑  收藏  举报