欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

agc027D - Modulo Matrix(构造 黑白染色)

程序员文章站 2022-04-14 20:47:12
题意 "题目链接" 构造一个$n n$的矩阵,要求任意相邻的两个数$a,b$,使得$max(a,b) \% min(a,b) \not = 0$ Sol 我的思路: 假设$mod = 1$,那么可以在第一行放2 3 4 5 $\dots$,第一列同理也这样放 对于任意位置$i$,一定满足要求的一个数 ......

题意

构造一个$n * n$的矩阵,要求任意相邻的两个数$a,b$,使得$max(a,b) % min(a,b) \not = 0$

sol

我的思路:

假设$mod = 1$,那么可以在第一行放2 3 4 5 $\dots$,第一列同理也这样放

对于任意位置$i$,一定满足要求的一个数是a[i - 1][j] * a[i][j - 1] / __gcd(a[i - 1][j], a[i][j - 1]) + 1

然而最后的数大到上天啊。。。

标算挺巧妙的,首先把整个图黑白染色,那么同色点之间是互不影响的。

考虑构造$mod = 1$的矩阵。

若白点的权值确定了,那么黑点的权值应当是所有相邻白点的$lcm$+1,

那所有白点的权值怎么确定呢?

考虑直接用素数填充对于正对角线和负对角线上的每个点分配一个不同的素数

那么任意白点的权值为所在正对角线上的素数 乘 负对角线的素数

这样算出来最大的$a_{ij} = 414556486388264 $,满足要求

不过为啥数组要开1000才能过???

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int maxn = 1e5 + 10;
int n;
int a[1001][1001], vis[maxn], prime[maxn], tot;
void getphi() {
    vis[1] = 1;
    for(int i = 2; i; i++) {
        if(!vis[i]) prime[++tot] = i;
        if(tot == 1000) break; 
        for(int j = 1; j <= tot && (i * prime[j] <= 10000); j++) {
            vis[i * prime[j]] = 1;
            if(!(i % prime[j])) break;
        }
    }
}
int lcm(int x, int y) {
    if(x == 0 || y == 0) return x + y;
    return x / __gcd(x, y) * y;
}
main() {
    getphi();
    cin >> n;
    if(n == 2) {
        printf("4 7\n23 10");
        return 0;
    }
    for(int i = 1; i <= n; i++) 
        for(int j = 1; j <= n; j++)
            if(!((i + j) & 1)) a[i][j] = prime[(i + j) / 2] * prime[n + (i - j) / 2 + (n + 1) / 2];
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            if(!a[i][j]) 
                a[i][j] = lcm(lcm(a[i - 1][j], a[i][j - 1]), lcm(a[i][j + 1], a[i + 1][j])) + 1;
    for(int i = 1; i <= n; i++, puts(""))
        for(int j = 1; j <= n; j++)
            cout << a[i][j] << " ";
    return 0;
}