top1编程
← 返回题目
题解

棋盘问题(普及组)

1 条题解

  • 0
    @ 2026-8-5 23:59:33

    P4705 棋盘问题(普及组)(基础)

    解题思路

    第一步:看懂题目。 一个 N×M 的棋盘,就像街道网格一样横竖交错。要数一数里面一共有多少个正方形、多少个长方形。注意:题目说的长方形不算正方形,正方形要单独数。

    第二步:先数正方形——按边长分类。 边长为 1 的正方形:横着有 N 个位置、竖着有 M 个位置,一共 N×M 个。边长为 2 的正方形:要占 2 行 2 列,横着有 N-1 个位置、竖着有 M-1 个位置,一共 (N-1)×(M-1) 个。依此类推,边长为 s 的正方形有 (N-s+1)×(M-s+1) 个。把所有边长的情况加起来,就是正方形总数。

    第三步:再数所有矩形——用“选线”的办法。 一个矩形由“选两条横线、选两条竖线”确定。横线一共有 N+1 条,从中选 2 条有 N×(N+1)/2 种选法;竖线一共有 M+1 条,从中选 2 条有 M×(M+1)/2 种选法。两者相乘,就是所有矩形(包含正方形)的总数。

    第四步:长方形数 = 总矩形数 - 正方形数。 题目要的长方形是不含正方形的矩形,所以用总矩形数减去正方形数就可以了。

    第五步:举个例子验证。 用 2×3 的棋盘:正方形有 6+2=8 个(边长 1 的有 2×3=6 个,边长 2 的有 1×2=2 个);总矩形是 (2×3/2)×(3×4/2)=3×6=18 个;长方形是 18-8=10 个,和样例一致。

    第六步:注意边界与数据大小。 N=1、M=1 时只有一个正方形、0 个长方形。N、M 最大到 100,N×(N+1)/2 可能达到几千,两个这样的数相乘会超过 int 的范围,所以要用 long long。

    参考代码

    // 棋盘问题:统计 N*M 棋盘中正方形和长方形(不含正方形)的个数
    #include <iostream>
    using namespace std;
    
    int main() {
        long long n, m;
        cin >> n >> m;
        long long squareCnt = 0;
        long long maxSide = n < m ? n : m; // 最大可能的正方形边长
        for (long long side = 1; side <= maxSide; side++) {
            // 边长为 side 的正方形有 (n-side+1)*(m-side+1) 个
            squareCnt += (n - side + 1) * (m - side + 1);
        }
        // 总矩形数 = 横线选 2 条 * 竖线选 2 条
        long long totalRect = (n * (n + 1) / 2) * (m * (m + 1) / 2);
        cout << squareCnt << " " << totalRect - squareCnt << endl;
        return 0;
    }
    

    复杂度分析

    循环从边长 1 到 min(N,M),时间复杂度 O(min(N,M)),对 100×100 的棋盘来说非常快。只用了几个变量,空间 O(1)。

    • 1