top1编程
← 返回题目
题解

Z字上的数字和

1 条题解

  • 0
    @ 2026-8-5 12:15:04

    解题思路

    “Z”字由哪几部分拼成?

    在 n×n 的方阵里,“Z”字由三部分组成:

    1. 第 1 行(Z 字最上面的横);
    2. 第 n 行(Z 字最下面的横);
    3. 辅对角线(连接上面横的右端到下面横的左端的斜线,也就是从右上到左下的那条对角线)。

    我们要把这三部分上所有元素加起来。

    怎么不重复、不遗漏地累加?

    第 1 行和第 n 行的所有格子都算,这个很简单。麻烦的是辅对角线:

    • 辅对角线的最右端格子 (1, n) 已经在第 1 行里了;
    • 辅对角线的最左端格子 (n, 1) 已经在第 n 行里了;
    • 所以,辅对角线只需要把中间部分(第 2 行到第 n-1 行)的数加进来。

    辅对角线上的格子满足:行号 + 列号 = n + 1(行、列都从 1 开始编号)。所以对第 i 行的格子,如果 i > 1 且 i < n 且 i + j == n + 1,就累加。

    一个容易出错的特殊情况:n = 1

    当 n = 1 时,第 1 行和第 n 行是同一个格子。但这个格子既属于“Z 字上面的横”,也属于“Z 字下面的横”,所以它要被累加两次。

    因此代码里要写成两个独立的 if:if (i == 1) s += x; 和 if (i == n) s += x;。这样当 n = 1 时,唯一的格子会被加两次,正好正确。

    验证样例: n=3 时,第 1 行 0+1+2=3,第 3 行 0+1+2=3,辅对角线中间只有 (2,2) 是 1,总和 3+3+1=7,与输出一致。

    参考代码

    // P4509 Z字上的数字和:第1行 + 第n行 + 辅对角线中间部分
    #include <iostream>
    using namespace std;
    int main() {
        int n, x;
        cin >> n;
        long long s = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                cin >> x;
                if (i == 1) s += x;                          // 第1行都在Z字上
                if (i == n) s += x;                          // 第n行也在Z字上(n=1时重合也算)
                if (i > 1 && i < n && i + j == n + 1) s += x; // 辅对角线中间部分
            }
        }
        cout << s << endl;
        return 0;
    }
    

    复杂度分析

    设方阵大小是 n×n。

    • 时间:两层循环要把 n×n 个格子全部读入并判断,时间复杂度是 O(n^2);
    • 空间:不需要存整个方阵,边读边累加,只用几个变量,空间复杂度是 O(1)。
    • 1