题解:洛谷 P2241 统计方形(数据加强版)
【题目来源】
洛谷:P2241 统计方形(数据加强版) - 洛谷(luogu.com.cn)
【题目描述】
有一个 \(n\times m\) 方格的棋盘,求其方格包含多少正方形、长方形(不包含正方形)。
【输入】
一行,两个正整数 \(n,m(n\le 5000,m\le 5000)\)。
【输出】
一行,两个正整数,分别表示方格包含多少正方形、长方形(不包含正方形)。
【输入样例】
2 3
【输出样例】
8 10
【核心思想】
-
问题分析:给定一个 \(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\) 则为正方形,否则为长方形。可以通过双重循环累加所有子矩形的数量,并分别统计正方形和长方形。
-
算法选择:
- 数学推导 / 双重循环:枚举所有可能的子矩形尺寸 \((i, j)\),其中 \(i\) 为高度(格数),\(j\) 为宽度(格数)。每个尺寸的子矩形在棋盘中的数量为 \((n-i+1)(m-j+1)\)。若 \(i=j\),则计入正方形总数;否则计入长方形总数。
- 优化:由于 \(n, m \le 5000\),双重循环 \(O(nm)\) 是可行的(2500万次操作),但需使用
long long避免溢出。
-
关键步骤:
- 读入:读取 \(n\) 和 \(m\)。
- 初始化:
square = 0,rectangle = 0。 - 枚举子矩形尺寸:循环 \(i\) 从 1 到 \(n\),\(j\) 从 1 到 \(m\):
- 计算该尺寸子矩形的数量:
cnt = (n - i + 1) * (m - j + 1)。 - 若
i == j,square += cnt。 - 否则,
rectangle += cnt。
- 计算该尺寸子矩形的数量:
- 输出:
square和rectangle。
-
时间/空间复杂度:
- 时间复杂度:\(O(n \times m)\),\(n, m \le 5000\) 时可接受。
- 空间复杂度:\(O(1)\)。
-
组合计数与数学:
- 子矩形计数公式:在 \(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
浙公网安备 33010602011771号