agc027D Modulu Matrix
-
构造一个 n ∗ n n*n n∗n的矩阵 a a a,满足没有两个元素相等, a i , j ≤ 1 e 15 a_{i,j}\le1e15 ai,j≤1e15。
-
对于所有相邻的格子值为 x , y x,y x,y,满足 m a x ( x , y ) % m i n ( x , y ) max(x,y)\%min(x,y) max(x,y)%min(x,y)全部为某一个固定的值 m m m。
-
n ≤ 500 n\le500 n≤500
Solution
-
对于这一类构造题,可以先思考一种简单的能够得到答案的通解,我们寻求的方法应该是简单、普遍的(有的时候需要一点分类讨论),然后再进行一些转化来优化构造的答案模型。一般来说不会有很复杂的模型,主要要培养构造的感觉。
-
注意到影响是相邻的,我们可以黑白染色(二分图),确定所有白点的数值,那么可以钦定每一个黑点的值是 l c m ( a x ) + 1 ( x 是 周 围 的 白 点 ) lcm(a_x)+1(x是周围的白点) lcm(ax)+1(x是周围的白点).
-
但是我们怎么保证不重复呢?
-
我们不妨假设所有白色点全部选质数,这样任意四个白点的乘积都不一样(可能需要对2特判)。
-
如果直接搞 n 2 n^2 n2个素数是不能满足1e15的,注意到我们求的是lcm,我们可以适当放一些重复的元素,也就是说,把每一个格子表示成两个素数的乘积。
-
只需要按照对角线乘同一个素数,两种对角线分别乘即可。
-
这样构造是不会超过1e15的。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define maxn 505
#define maxm 5000005
#define ll long long
using namespace std;
int n,i,j,k;
int tot,pri[maxm],bz[maxm];
ll a[maxn][maxn];
void getpri(){
for(int i=2;i<maxm;i++){
if (!bz[i]) pri[++tot]=i;
for(int j=1;j<=tot&&i*pri[j]<maxm;j++){
bz[i*pri[j]]=1;
if (i%pri[j]==0) break;
}
}
}
ll gcd(ll x,ll y){
return (x%y==0)?y:gcd(y,x%y);}
ll lcm(ll x,ll y){
return x/gcd(x,y)*y;}
ll Lcm(ll a,ll b,ll c,ll d){
ll x=1;
if (a) x=lcm(x,a);
if (b) x=lcm(x,b);
if (c) x=lcm(x,c);
if (d) x=lcm(x,d);
return x;
}
int main(){
freopen("ceshi.in","r",stdin);
// freopen("ceshi.out","w",stdout);
scanf("%d",&n),getpri(),k=0;
if (n==2) printf("5 4\n2 3\n"),exit(0);
for(i=1;i<=n;i++) for(j=1;j<=n;j++) a[i][j]=1;
for(i=1;i<=n;i++) for(j=1;j<=n;j++) if ((i+j)%2==0) a[i][j]*=pri[(i+j)/2];
for(i=1;i<=n;i++) for(j=1;j<=n;j++) if ((i+j)%2==0) a[i][j]*=pri[(i-j+n-(n&1))/2+n];
for(i=1;i<=n;i++) for(j=1;j<=n;j++) if ((i+j)%2)
a[i][j]=Lcm(a[i-1][j],a[i][j-1],a[i+1][j],a[i][j+1])+1;
for(i=1;i<=n;i++,printf("\n")) for(j=1;j<=n;j++) printf("%lld ",a[i][j]);
}