#构造,黑白染色#AT4378 [AGC027D] Modulo Matrix

题目

构造一个 \(n*n(n\leq 500)\) 的矩阵,满足元素均为正整数,不超过 \(10^15\) 且互不相同,

并且相邻两数若较大的为 \(x\),较小的为 \(y\),那么任意相邻两数 \(x\bmod y\) 都相同。


分析

其实相邻在构造题中有一个很好的办法就是黑白染色,并且让 \(x\bmod y=1\) 能使 \(x\) 尽量小。

综合考虑值域和互不相同,可以发现让白格为四个黑格的最小公倍数加一,那么黑格互不相同就可以让白格也尽量不同。

有一个很妙的方法就是黑格所在的对角线标记一个质数,这样每个黑格被正对角线和反对角线的两个质数相乘,

那么由于至少有一条对角线不同,那么黑格一定互不相同,白格也对应的互不相同,当然 \(n=2\) 的情况要特判。

然后前 \(2n\) 个质数不超过 \(16n\),所以四个数的最小公倍数理论上最大为 \(4*10^{15}\) 实际上肯定达不到这个上界


代码

#include <iostream>
using namespace std;
const int M=8011,N=511,dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int v[M+1],p[M+1],n,m; typedef long long lll; lll a[N][N];
lll gcd(lll x,lll y){return y?gcd(y,x%y):x;}
int main(){
	ios::sync_with_stdio(0);
	cin>>n,v[1]=1;
	if (n==2){
		cout<<"2 3\n5 16\n";
		return 0;
	}
	for (int i=2;i<=M;++i)
	if (!v[i]){
		p[++m]=i;
		for (int j=i;j<=M;j+=i) v[j]=1;
	}
	for (int i=1;i<=n;++i)
	for (int j=1;j<=n;++j)
	if ((i+j+1)&1)
		a[i][j]=p[(i+j)>>1]*p[n+(i-j+n+1)/2];
	for (int i=1;i<=n;++i)
	for (int j=1;j<=n;++j)
	if ((i+j)&1){
		a[i][j]=1;
		for (int k=0;k<4;++k){
			int x=i+dx[k],y=j+dy[k];
			if (x<1||y<1||x>n||y>n) continue;
			a[i][j]=a[i][j]/gcd(a[i][j],a[x][y])*a[x][y];
		}
		++a[i][j];
	}
	for (int i=1;i<=n;++i)
	for (int j=1;j<=n;++j)
	    cout<<a[i][j]<<(char)(j==n?10:32);
	return 0;
}
posted @ 2022-03-20 16:48  lemondinosaur  阅读(38)  评论(0编辑  收藏  举报