题目
解法一
思路
n,m范围只有100,所以枚举左上角,枚举右下角,判断是正方形还是长方形
时间复杂度
枚举1个是O(n2),所以复杂度为O(n4)
代码
#include<stdio.h>
int main()
{
int n,m,a=0,b=0,i,j,k,l;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)
for(k=i;k<=n;++k)
for(l=j;l<=m;++l)
if(k-i==l-j) a++;
else b++;
printf("%d %d",a,b);
}
解法二
思路
从边长方向考虑:n行m列的大矩形内能找出多少i行j列的小矩形?
小矩形一共有i行,它的第1行可以在大矩形的第1—n-i+1行,它的最后1行可以在大矩形的第i—n行
小矩形一共有j列,它的第1列可以在大矩形的第1—m-j+1列,它的最后1列可以在大矩形的第j—m列
所以枚举边长i 和 j,可以有(n-i+1)(m-j+1)个
时间复杂度
两重循环枚举边长,O(n2)
代码
#include<stdio.h>
int main()
{
int n,m,a=0,b=0,i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)
if(i==j) a+=(n-i+1)*(m-j+1);
else b+=(n-i+1)*(m-j+1);
printf("%d %d",a,b);
}
解法三
思路
前面解法看起来很有规律,所以我们是否能推出一个公式?
先考虑能找出多少个矩形(长方形+正方形)
- 思考方向一:把上面思路二的两重for循环展开,即把(n-i+1)(m-j+1)里的i和j扩展开,就是(1+2+3+……+n)(1+2+3+……+m),用等差数列求和公式得到n(n+1)m(m+1)/4
- 思考方向二:相当于从n+1个横线和m+1个竖线中,任选2条横线,任选2条竖线,有多少种选法。因为每一种选法都可以构成一个矩形。用组合数得到 C(n+1,2)*C(m+1,2)=n(n+1)m(m+1)/4
再推出正方形的个数公式,减去就是长方形的个数
正方形的个数公式推导:
时间复杂度
套公式直接出解,O(1)
代码
#include<stdio.h>
int main()
{
int n,m,a,b,t;
scanf("%d%d",&n,&m);
t=n<m ? n : m;
a=(n*m+n+m+1)*t-t*(t+1)/2*(n+m+2)+t*(t+1)*(2*t+1)/6;
b=n*m*(n+1)*(m+1)/4;
printf("%d %d",a,b-a);
}