洛谷P2241 统计方形(数据加强版)C语言

题目背景

1997年普及组第一题

题目描述

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

输入格式

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

输出格式

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

输入输出样例

输入 #1复制

2 3

输出 #1复制

8 10

思路简介:

此类有限解的题通过枚举来做比较简单粗暴,难点是枚举题的三步走:

一、找到合适的枚举变量,合适便是指,当有多个可能的枚举变量时,思考能否简化枚举量,往往结合数学思想,一般有几个枚举变量便有几重循环;

、确定枚举变量的范围;

三、确定如何对枚举变量进行操作和判断。

比如此处,有多种枚举变量可以选择,如棋盘中的点,线等等。但显然此处可以利用数学公式大大优化思路。棋盘中的矩形个数显然是好求的,利用高中数学的排列组合。矩形有四条边,两横两竖。棋盘由n*m个小方格组成,有n+1竖线,m+1横线。分别从竖线中选2条(与顺序无关)所以总的矩形个数就是

而显然矩形除了正方形就是长方形,即矩形个数=正方形个数+长方形个数。且正方形要求四边相等,所以更加好求。用矩形的个数减去正方形的个数显然就得到了长方形的个数。

那怎么求正方形个数呢?可利用正方形的四边长相等,那怎么确定枚举变量呢?是看边还是点呢?枚举题要尽量的思考如何优化枚举变量和对枚举变量的判断和操作。对于此题,在棋盘中,我们可利用以正方形的边长的长度作为枚举变量,正方形的边长显然是从1开始,而最大边长取决于min{n,m}。这样一分析,我们就完成了解枚举题的第一步和第二步,即找到合适的枚举变量和其范围。最重要也是最“麻烦”的第三步,便是确定如何对枚举变量进行操作和判断。

 在此处,“难点”便是如何确定边长为确定值时在矩形中有多少个正方形。我们都知道,正方形也只不过是特殊的矩形,既然我们前面在利用竖线x横线的方式确定矩形的个数,我们同样也可以利用此方法来确定当边长确定时正方形的个数。也可以其他方法,比如,矩形显然也是由矩形构成的,最小的矩形便是只有一条边的正方形,所以显然可以用递归,一层层递归。其实也可以用公式法,对于解决这个问题,有个公式需要知道,假设一个矩阵长为5,宽为4,那么求一个矩形中的正方形个数公式为:4*5+【(4-1)(5-1)】+【(4-2)(5-2)】+【(4-3)(5-3)】,因为(4-4)*(5-4)是0,没实际意义,所以不需要再继续。所以i的范围是1到min{n,m}。

AC代码如下

​#include<stdio.h>
long m,n,x,y;//在32位编译系统int和long都是占4字节,但64位long是占8字节,洛谷的编译系统应该是64位的。变量都开long一来是为了压行,二来是为了防止在计算矩形个数时数据溢出。
long min(long a,long b) {
    return a<b?a:b;
}
int main() {
    scanf("%ld%ld",&m,&n);
    x=((m+1)*m/2)*((n+1)*n/2);//x记录矩形的总个数
    for(long i=1; i<= min(m,n); i++) {//i作为枚举变量,代表正方形的边长
        y+=(m-i+1)*(n-i+1);//y记录正方形的个数
    }
    printf("%ld %ld", y, x-y);//x-y便是长方形的个数
    return 0;
}

​

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Prudento

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值