题解:洛谷 P2241 统计方形(数据加强版)

【题目来源】

洛谷:P2241 统计方形(数据加强版) - 洛谷(luogu.com.cn)

【题目描述】

有一个 \(n\times m\) 方格的棋盘,求其方格包含多少正方形、长方形(不包含正方形)。

【输入】

一行,两个正整数 \(n,m(n\le 5000,m\le 5000)\)

【输出】

一行,两个正整数,分别表示方格包含多少正方形、长方形(不包含正方形)。

【输入样例】

2 3

【输出样例】

8 10

【核心思想】

  1. 问题分析:给定一个 \(n \times m\) 的方格棋盘,需要统计其中包含的正方形长方形(不包括正方形)的数量。对于每个由 \(i \times j\) 个小方格组成的子矩形(\(1 \le i \le n, 1 \le j \le m\)),它在棋盘中的位置数为 \((n-i+1) \times (m-j+1)\)。若 \(i = j\) 则为正方形,否则为长方形。可以通过双重循环累加所有子矩形的数量,并分别统计正方形和长方形。

  2. 算法选择

    • 数学推导 / 双重循环:枚举所有可能的子矩形尺寸 \((i, j)\),其中 \(i\) 为高度(格数),\(j\) 为宽度(格数)。每个尺寸的子矩形在棋盘中的数量为 \((n-i+1)(m-j+1)\)。若 \(i=j\),则计入正方形总数;否则计入长方形总数。
    • 优化:由于 \(n, m \le 5000\),双重循环 \(O(nm)\) 是可行的(2500万次操作),但需使用 long long 避免溢出。
  3. 关键步骤

    • 读入:读取 \(n\)\(m\)
    • 初始化square = 0rectangle = 0
    • 枚举子矩形尺寸:循环 \(i\) 从 1 到 \(n\)\(j\) 从 1 到 \(m\)
      • 计算该尺寸子矩形的数量:cnt = (n - i + 1) * (m - j + 1)
      • i == jsquare += cnt
      • 否则,rectangle += cnt
    • 输出squarerectangle
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n \times m)\)\(n, m \le 5000\) 时可接受。
    • 空间复杂度:\(O(1)\)
  5. 组合计数与数学

    • 子矩形计数公式:在 \(n \times m\) 网格中,大小为 \(i \times j\) 的子矩形有 \((n-i+1)(m-j+1)\) 个。
    • 分类:正方形 \(i=j\),长方形 \(i \ne j\)
    • 适用场景:这类“统计网格中特定形状数量”的问题,常用枚举尺寸并利用位置数公式解决。

【解题思路】

【算法标签】

普及- #模拟

【代码详解】

#include <bits/stdc++.h>  // 包含常用的头文件
using namespace std;

int main()
{
    // 定义变量
    long long n, m, z = 0, c = 0;  // n 和 m 是输入的两个维度,z 和 c 是计算结果
    // 注意:5000*5000 的累加结果会超过 int 的最大范围,因此使用 long long

    // 输入 n 和 m
    cin >> n >> m;

    // 双重循环遍历 i 和 j
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            // 计算 z:累加 min(i, j)
            z += min(i, j);
            // 计算 c:累加 i*j - min(i, j)
            c += i * j - min(i, j);
        }
    }

    // 输出结果 z 和 c
    cout << z << " " << c;

    return 0;  // 程序结束
}

【运行结果】

2 3
8 10
posted @ 2026-08-31 09:26  团爸讲算法  阅读(14)  评论(0)    收藏  举报