P2241 统计方形(数据加强版)- 题解

P2241 统计方形(数据加强版)

题目背景

1997年普及组第一题

题目描述

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

输入格式

一行,两个正整数 $n,m$($n \leq 5000,m \leq 5000$)。

输出格式

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

输入输出样例 #1

输入 #1

2 3

输出 #1

8 10

思路讲解

我们要先思考,正方形有多少个?
先从最简单的1*2的格子来看,正方形有2个,2*2的格子呢?是5个正方形。
再来看3*4的格子呢?你似乎会发现正方形的数量有某些规律。
显然,正方形的个数就是以点(i,j)为左上角,以(i+k,j+k)为右下角,(i+k<=n,j+k<=m),的正方形数量
image
这样遍历一遍确实能解决,但是你再仔细观察,正方形的数量似乎与对角线有关,于是你重新从1*2的矩形看,一直看到3*4的矩形,你发现1*2的矩形是3*4的子集。
没错,你发现了,正方形的数量就是这个大矩形的对角线的xy的乘积并累加。
image
但是对角线并不是从左上到右下,而是图上这种对角线,这种正方形的对角线。
正方形数量就是1*2+2*3+3*4。
那么长方形呢?长方形我推了很长时间都没推出来,于是想到正难则反。
我们不推长方形,我们找所有的矩形,之后减去正方形的数量就是长方形的数量。
矩形数量就是(n+1)*n/2*(m+1)*m/2。减去正方形数量就是长方形数量。

题解代码

#include <iostream>
using namespace std;
#define ll long long
ll sq,l;
ll n,m;
int main(){
    cin>>n>>m;
    if(n>m){
        ll t=n;n=m;m=t;
    }
    for(ll i=1,j=m-n+1;i<=n,j<=m;i++,j++){
        sq+=(i*j);
    }
    l=(n+1)*n/2*(m+1)*m/2;
    cout<<sq<<" "<<l-sq;
}
posted @ 2026-11-02 09:17  ysMip  阅读(1)  评论(0)    收藏  举报