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

本文详细解析了一种构造特殊矩阵的算法,该矩阵要求任意相邻两数满足特定条件。通过黑白染色法与素数填充策略,确保了矩阵中元素满足最大公约数条件下不整除的特性。

题意

题目链接

构造一个\(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;
}

转载于:https://www.cnblogs.com/zwfymqz/p/9718849.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值