xmlns="http://www.w3.org/2000/svg"style="display:网格中正方形与长方形数量的数学推导与高效计算在算法竞赛和编程面试中,经常遇到一类经典问题:给定一个n\timesmn×m的方格棋盘,求其中包含多少个正方形、多少个长方形(不包含正方形)。本文将从原理出发,详细推导其数学公式,并提供两种实现方式的对比分析,最终给出最优解。典型题目链接:P2241统计方形(数据加强版)/>一、问题理解题目中的“n\timesmn×m方格”指的是由nnn行、mmm列单位小方格组成的矩形网格。我们需要统计:所有可能的正方形区域(边长为\min(n,m)min(n,m),且边与网格线对齐);所有可能的长方形区域(不含正方形),即矩形中长宽的部分。注意:这里的“矩形”包括正方形,而“长方形”在本题语境下特指“非正方形的矩形”。/>二、总矩形数的推导任意一个矩形由其上下边界和左右边界唯一确定。在一个n\timesmn×m的网格中:水平方向有n+n+1n+1条横线,从中任选条作为上下边界,共有n+\frac{n(n+1)}{2}style="height:-2.655em;">2style="top:-3.485em;">n(n+1)style="height:0.345em;">种选法;垂直方向有m+m+1m+1条竖线,从中任选条作为左右边界,共有m+\frac{m(m+1)}{2}style="height:-2.655em;">2style="top:-3.485em;">m(m+1)style="height:0.345em;">种选法。因此,所有矩形的总数为:T=\frac{m(m+1)}{2}style="margin-right:0.1389em;">T=style="height:-2.314em;">2style="top:-3.677em;">n(n+1)style="height:0.686em;">⋅style="height:-2.314em;">2style="top:-3.677em;">m(m+1)style="height:0.686em;">该公式简洁且高效,是后续计算的基础。漫画演示:/>/>三、正方形数量的两种求法方法一:枚举边长(循环法)设正方形边长为kstyle="margin-right:0.0315em;">k(1minm)1≤style="margin-right:0.0315em;">k≤min(n,m)),则其左上角可在(+1)(n−style="margin-right:0.0315em;">k+1)×(m−style="margin-right:0.0315em;">k+1)个位置放置。因此,正方形总数为:S=0.0576em;">S=style="height:0.0315em;">k=1style="top:-3.05em;">∑style="top:0em;">min(n,m)style="height:1.3021em;">(n−style="margin-right:0.0315em;">k+1)(m−style="margin-right:0.0315em;">k+1)该方法直观易懂,时间复杂度为Omin0.0278em;">O(min(n,m))。对于n50005000n,m≤5000的数据范围,最多执行5000次循环,在实际运行中完全可接受。方法二:闭式公式(数学优化)通过代数变换,上述求和可转化为闭式表达。令a=m)a=min(n,m),b=m)b=max(n,m),则:S=0.0576em;">S=style="height:0.0315em;">k=1style="top:-3.05em;">∑style="top:0em;">astyle="height:1.3021em;">(a−style="margin-right:0.0315em;">k+1)(b−style="margin-right:0.0315em;">k+1)=style="height:0em;">x=1style="top:-3.05em;">∑style="top:0em;">astyle="height:1.2671em;">x(b−a+x)令d=ad=b−a,利用求和公式∑=\frac{a(a+1)}{2}style="position:0em;">∑x=style="height:-2.655em;">2style="top:-3.485em;">a(a+1)style="height:0.345em;">和∑=\frac{a(a+1)(2a+1)}{6}style="position:0em;">∑xstyle="height:0.05em;">2=style="height:-2.655em;">6style="top:-3.485em;">a(a+1)(2a+1)style="height:0.345em;">,可得:S=0.0576em;">S=d⋅style="height:-2.314em;">2style="top:-3.677em;">a(a+1)style="height:0.686em;">+style="height:-2.314em;">6style="top:-3.677em;">a(a+1)(2a+1)style="height:0.686em;">=style="height:-2.314em;">6style="top:-3.677em;">a(a+1)(3b−a+1)style="height:0.686em;">此即正方形数量的闭式公式,计算仅需常数时间。验证示例以n=3n=2,m=3为例:a=3a=2,b=3S=0.0576em;">S=style="height:-2.655em;">6style="top:-3.485em;">2⋅3⋅(9−2+1)style="height:0.345em;">=style="height:-2.655em;">6style="top:-3.394em;">6⋅8style="height:0.345em;">=8与手动枚举结果一致。漫画演示:/>/>四、长方形数量的计算根据容斥原理:长方形数量=S长方形数量=总矩形数−正方形数量=style="margin-right:0.1389em;">T−style="margin-right:0.0576em;">S无需单独枚举非正方形矩形,避免了复杂的分类讨论。/>五、代码实现对比循环法(清晰直观)longsquares=0;intmin=Math.min(n,m);for(intk=1;k<=min;k++){squares+=(long)(n-k+1)*(m-k+1);}闭式法(高效优雅)longa=Math.min(n,m);longb=Math.max(n,m);longsquares=a*(a+1)*(3*b-a+1)/6;注意:所有变量必须使用long类型,防止中间结果溢出。当n=5000n=m=5000时,最大中间值约为2.52.510^{11}2.5×10style="height:0.05em;">11,远超int范围(约2\times10^92×10style="height:0.05em;">9)。漫画演示:/>/>六、效率与适用性分析维度循环法闭式法时间复杂度Omin0.0278em;">O(min(n,m))Ostyle="margin-right:0.0278em;">O(1)实际运行时间微秒级(≤5000次)纳秒级代码长度稍长极简可扩展性仅适用于较小规模适用于极大nmn,m(只要不超long)通用性仅适用于标准网格正方形计数同左虽然在本题数据范围内两者性能差异在0ms,但闭式法体现了“用数学优化算法”的核心思想,是更优的工程实践。/>七、公式的适用边界该闭式公式仅适用于以下条件同时满足的情形:网格完整无缺(无障碍物);正方形边必须与网格线平行(不允许旋转);统计所有尺寸的正方形总数。若问题变体涉及障碍物、旋转正方形、仅统计特定边长、或三维扩展等,则需重新建模,不能直接套用此公式。漫画演示:/>/>八、总结总矩形数:T=\frac{m(m+1)}{2}style="margin-right:0.1389em;">T=style="height:-2.314em;">2style="top:-3.677em;">n(n+1)style="height:0.686em;">⋅style="height:-2.314em;">2style="top:-3.677em;">m(m+1)style="height:0.686em;">正方形数:S=0.0576em;">S=style="height:-2.314em;">6style="top:-3.677em;">a(a+1)(3b−a+1)style="height:0.686em;">,其中a=\max(n,m)a=min(n,m),b=max(n,m)长方形数:Tstyle="margin-right:0.1389em;">T−style="margin-right:0.0576em;">S推荐在实际编程中优先采用闭式公式法,它不仅效率更高,而且代码简洁、逻辑严谨,是解决此类组合计数问题的最佳实践。