构造题

构造不会一点。

填数游戏(241215 热身赛)

有一个 \(n\times m\) 的矩阵,将 \(1,2,\cdots,n\times m\) 填入矩阵中,满足:

  • 每个位置恰好填入一个数字;
  • \(1,2,\cdots,n\times m\) 中每个数字恰好出现一次;
  • 矩阵每一行数字的和都不是质数,每一列数字的和都不是质数。

输出构造的 \(n\times m\) 矩阵,无解输出 \(\texttt{-1}\)

\(1\le n,m\le1000\)

首先考虑简单的情况:若 \(n=1\)\(m=1\) 则无解,但是 \(n=m=1\) 时有解,即输出一个 \(\texttt1\)

另外,显然 \(n,m\) 的顺序不影响答案,只需考虑 \(n<m\) 的情况,\(n>m\) 的情况输出转置即可。

观察所给的样例:\(n=2,m=3\),构造矩阵 \(\begin{pmatrix}1&2&3\\5&4&6\end{pmatrix}\)。猜想这样的构造方式是把原本自然排列的矩阵 \(\begin{pmatrix}1&2&3\\4&5&6\end{pmatrix}\) 稍微调整得来的。先考虑 \(n=2\) 的情况。

容易想到,如果让所有列的和都是偶数,那么就可以满足列的条件了。而偶数 = (偶 + 偶) 或者 (奇 + 奇),因此把上下的奇偶错开即可。对于最后一列,分别是 \(m\)\(2m\),因此不用动。

进一步地,如果 \(m\) 是偶数,那么第一行:奇偶奇偶…,第二行:奇偶奇偶…,因此直接输出 \(\begin{pmatrix}1&2&\cdots &m\\m+1&m+2&\cdots&2m\end{pmatrix}\) 即可。

如果 \(m\) 是奇数,正如上面所说,最后一列不用调整,只需调整前 \(m-1\) 列,那么将

  • 第一行:奇偶奇偶…奇偶 \(m\)
  • 第二行:偶奇偶奇…偶奇 \(2m\)

改为

  • 第一行:奇偶奇偶…奇偶 \(m\)
  • 第二行:奇偶奇偶…奇偶 \(2m\)

即可。

对于 \(n>2\) 的情况,输出自然排列即可,这是因为第 \(i\) 行的和 \(\dfrac12m(m+1)\cdot i\) 和第 \(j\) 列的和

\[\dfrac12n(n-1)m+nj=n\left[\dfrac{(n-1)m}2+j\right]=\dfrac n2[(n-1)m+2j] \]

一定都是合数。

代码:

点击查看代码
#include <bits/stdc++.h>
#define f(x, y, z) for (int x = (y); x <= (z); ++x)
using namespace std;
int const N = 1e3 + 10;
int n, m, a[N][N];

signed main() {
    
    cin >> n >> m;
    if (n == 1 && m == 1) return cout << "1\n", 0;
    if (n == 1 || m == 1 || (n == 2 && m == 2)) return cout << "-1\n", 0;

    int nn = max(n, m), mm = min(n, m);
    if ((n == 2 || m == 2) && (nn % 2 == 1)) {
        f(j, 1, nn) a[1][j] = j;
        f(j, 1, nn - 2) a[2][j] = nn + j + 1;
        a[2][nn - 1] = nn + 1;
        a[2][nn] = nn + nn;
    } else f(i, 1, mm) f(j, 1, nn) a[i][j] = nn * (i - 1) + j;

    if (n < m) f(i, 1, mm) {
        f(j, 1, nn) cout << a[i][j] << ' ';
        cout << '\n';
    } else f(i, 1, nn) {
        f(j, 1, mm) cout << a[j][i] << ' ';
        cout << '\n';
    }
    
    return 0;
}
posted @ 2024-12-18 11:37  f2021ljh  阅读(4)  评论(0编辑  收藏  举报