ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

等差等比数列公式总结与Python代码实现:从算法复杂度到求和技巧

等差等比数列公式总结与Python代码实现:从算法复杂度到求和技巧 简介《等差、等比数列公式总结.pdf》是一份面向高中数学学习者与备考者的公式速查手册系统梳理了等差数列与等比数列的定义、通项公式及变式、前n项和公式、几何意义、常用性质并给出两类数列的类比对照帮助读者快速建立知识框架。等差中项、等比中项、片段和等典型性质以及分组求和、裂项相消、错位相减等常见求和方法也均有涉及从基础定义到进阶变式逐层梳理重点公式以条目化呈现便于对照记忆和快速定位适合在课后巩固、考前冲刺或解题时随时查阅。资源仅包含1个PDF文档压缩包约193KB轻量易用可打印或放入移动设备离线查看。目前已有408人学习下载是一份简洁实用的数列公式总结能有效节省整理笔记的时间。1. 从算法复杂度题反推等差数列公式的用途第一次把等差等比公式当回事不是在数学课上而是在分析一段二分暴力的代码复杂度时外层循环跑 $n$ 轮内层每轮迭代次数递减总迭代次数恰好是 $12\dotsn$另一段递归的调用次数呈 $1qq^2\dots$ 的形状。没有公式只能写循环硬加有了公式直接 O(1) 出结果。这份《等差、等比数列公式总结》PDF 把定义、通项、变式、前 n 项和、性质以及分组求和、裂项求和、错位相减三种套路压缩在一份速查讲义里。适合三类人需要系统梳理公式推导逻辑的学生、要给学生出题或讲题的老师以及在代码里想用封闭式替代循环累加的开发者。下文直接按公式拆解→代码复现→边界处理的顺序把这套内容过一遍。2. 等差数列通项变形、前n项和与直线模型的对应2.1 定义与通项公式的三种写法等差数列的定义写作 $a_{n1}-a_nd$其中 $d$ 是公差。这个递推式在程序里就是一个a d的循环。通项公式 $a_na_1(n-1)d$ 表达的是一次线性关系以 $n$ 为自变量$a_n$ 是一条斜率为 $d$ 的直线。讲义里给的变式 $a_na_m(n-m)d$ 更实用它允许从任意已知项 $a_m$ 出发推算第 $n$ 项不必先回推首项。给定任意两项 $a_n$、$a_m$公差可以反推为 $d\frac{a_n-a_m}{n-m}$。三组公式配合已知任意两个独立参数就能解出其余参数对应到代码里是几个纯函数def ap_term(a1, d, n): # 等差数列第 n 项a1 (n-1)*d return a1 (n - 1) * d def ap_term_from_am(am, d, m, n): # 从已知第 m 项出发求第 n 项a_m (n-m)*d return am (n - m) * d def ap_common_diff(an, am, n, m): # 由任意两项反推公差调用时需保证 n ! m return (an - am) / (n - m)ap_term的参数是首项a1、公差d、下标n返回第 $n$ 项时间复杂度 O(1)。ap_term_from_am在题目只给出中间某项和公差时更省事省去先求首项的中间步骤。ap_common_diff返回浮点数如果题目保证所有项是整数可以先用(an - am) % (n - m) 0判断能否整除再做整数除法避免精度丢失。实际写算法题时我会把这类纯计算函数放在一个sequences模块里配几组 doctest后续所有等差数列相关分支都复用同一套实现。2.2 前n项和公式的几何意义Sn是二次函数公差藏在系数里前 n 项和有两个等价写法$S_n\frac{n(a_1a_n)}{2}$ 和 $S_n\frac{n(2a_1(n-1)d)}{2}$。第一个适合已知首项和末项的场景本质是倒序相加正序写一遍反序写一遍每对相加都是 $a_1a_n$共 $n$ 对再除以 2。第二个写法展开后是 $S_n\frac{d}{2}n^2(a_1-\frac{d}{2})n$这是关于 $n$ 的二次函数。二次项系数是 $\frac{d}{2}$常数项恒为 0。反过来如果题目给出 $S_nAn^2Bn$可以直接读出公差 $d2A$、首项 $a_1AB$。这个结论在做数列判断题时很常用看到 $S_n$ 的表达式不是二次函数或者常数项不为 0就能判定不可能是等差数列的前 n 项和。下面是一段随机验证脚本比较公式求和与循环累加的结果是否一致import random def ap_sum_formula(a1, d, n): # 公式求和n * (2*a1 (n-1)*d) / 2 return n * (2 * a1 (n - 1) * d) // 2 def ap_sum_loop(a1, d, n): total 0 for i in range(n): total a1 i * d return total for _ in range(1000): a1 random.randint(-100, 100) d random.randint(-10, 10) n random.randint(1, 100) assert ap_sum_formula(a1, d, n) ap_sum_loop(a1, d, n)代码里用整除// 2而不是浮点除法是因为 $n \cdot (2a_1(n-1)d)$ 一定是偶数这是等差数列求和的整数性质浮点除法反而可能引入 1e-15 级别的误差。随机参数的取值范围覆盖了负首项、负公差循环 1000 次全部通过说明公式在整数场景下是封闭且可替代循环的。另一个验证角度是对 $S_n$ 做差分$S_n-S_{n-1}a_n$这也是沟通递推定义与二次函数模型的桥梁。已知条件常用公式复杂度边界注意首项、末项、项数$S_n \frac{n(a_1a_n)}{2}$O(1)项数为正整数首项、公差、项数$S_n \frac{n(2a_1(n-1)d)}{2}$O(1)$n0$ 时结果为 0$S_n An^2Bn$$d2A$$a_1AB$O(1)常数项必须为 02.3 用Python验证等差数列的性质下标和相等则项和相等讲义里性质①是若 $pqmn$则 $a_pa_qa_ma_n$。这个性质成立的根源是通项为下标的一次函数。但要注意它是必要条件不是充分条件。比如 $1,2,4,5,7$ 这个序列也能满足下标和相等则项和相等但它不是等差数列。真正可靠的判定方法是差分数列全部相等。下面代码同时实现差分数列判定和性质抽查def is_arithmetic(seq): # 通过差分数列判断是否等差数列 if len(seq) 2: return True d seq[1] - seq[0] return all(seq[i] - seq[i - 1] d for i in range(2, len(seq))) def property_spot_check(seq): # 随机抽下标验证 pq mn 时项和相等 n len(seq) for _ in range(1000): p, q, m random.sample(range(n), 3) s p q - m if 0 s n and seq[p] seq[q] ! seq[m] seq[s]: return False return Trueis_arithmetic一次遍历比较相邻差分时间 O(n)比套用 $S_n$ 二次函数直接。property_spot_check里random.sample取出的三个下标可能使s越界所以必须加上0 s n的前置判断。性质抽查适合作为单元测试的补充但不能作为主判据。判断一个序列是否为等差数列永远以差分全相等为准。3. 等比数列错位相减推导、前n项和的边界条件与数值实现3.1 从递推定义到通项公式公比q的边界值等比数列的定义式是 $\frac{a_{n1}}{a_n}q$$q$ 为公比。写成乘法递推 $a_{n1}a_n q$ 后通项收敛为 $a_na_1 q^{n-1}$。这个定义隐含一个约束所有项都不能为 0否则后一项无法通过除法定义公比。因此 $0,0,0,\dots$ 虽然满足乘法递推但不满足等比数列的比值定义做题时通常直接排除。通项变式 $a_na_m q^{n-m}$ 与等差数列变式逻辑相同区别是把加法换成乘法。已知两项反推公比时 $q\sqrt[n-m]{a_n/a_m}$要求 $a_n/a_m0$否则实数范围内无解或出现多解代码里容易被忽略。def gp_term(a1, q, n): # 等比数列通项a1 * q^(n-1) if n 1: return a1 return a1 * (q ** (n - 1)) def gp_common_ratio(an, am, n, m): # 反推公比q (an/am)^(1/(n-m)) if n m: raise ValueError(n 不能等于 m) if am 0: raise ValueError(分母不能为 0) return (an / am) ** (1 / (n - m))gp_term对负公比场景也能正确处理Python 的q ** (n-1)在指数为偶数时返回正数、奇数时返回负数与数学定义一致。gp_common_ratio返回浮点数当an / am为负数时会得到复数结果工程上需要先判断符号再决定是否取绝对值后补符号。如果题目保证公比为整数更好的做法是先取近似整数回代验证a_m * q**(n-m) a_n避免浮点误差导致误判。等比比等差多出的这层边界本质上来自乘法和除法的符号敏感性。3.2 错位相减推导前n项和q1的单独分支等比数列前 n 项和公式的推导是错位相减的标准示范。设 $S_na_1a_1q\dotsa_1q^{n-1}$两边同时乘以 $q$ 得到 $qS_na_1qa_1q^2\dotsa_1q^n$。用前者减后者中间 $n-1$ 项全部抵消剩下 $(1-q)S_na_1(1-q^n)$。这一步必须停下来判断 $1-q$ 是否为 0当 $q1$ 时等式左边为 0无法通过除法求解这时候数列退化为常数列前 n 项和是 $n a_1$。当 $q\neq1$ 时才有 $S_n\frac{a_1(1-q^n)}{1-q}$。讲义里另一个写法 $\frac{a_1(q^n-1)}{q-1}$ 分子分母同时变号适合 $q1$ 时使用避免分子分母同时为负的不适感。def gp_sum_naive(a1, q, n): # 等比数列前 n 项和q 1 分支不可省略 if q 1: return a1 * n return a1 * (1 - q ** n) / (1 - q)这段代码最关键的参数是q它决定走哪个分支。q 1时若沿用除法公式(1 - q)为 0运行时报 ZeroDivisionError。即使不报错在q无限接近 1 时分子分母同时趋向 0结果也会不稳定。所以等比数列求和代码里q 1的判断必须放在最前面。错位相减的推导过程本身也是第 4 章等差×等比求和的原始模板建议把这一步手推一遍比直接背公式更能记住适用条件。3.3 等比求和代码的浮点稳定性与取值边界gp_sum_naive数学上正确工程上还有两个坑。第一个是浮点误差$q$ 接近 1 时1 - q**n和1 - q都是小量相除会放大相对误差$n$ 很大且 $|q|1$ 时q**n可能溢出为inf。第二个是符号处理1 - q**n在 $q1$ 时为负1-q也为负分子分母同号结果为正但中间过程的绝对值很大可能丢失精度。常见做法是根据 $|q|$ 选择等价形式def gp_sum_stable(a1, q, n): # 稳定的等比求和根据 |q| 选择公式形式 if q 1: return a1 * n if n 0: return 0.0 if abs(q) 1: return a1 * (q ** n - 1) / (q - 1) return a1 * (1 - q ** n) / (1 - q)当 $|q|1$ 时改用(q**n - 1) / (q - 1)分子分母都朝正方向增长避免两个小数相减当 $0q1$ 时保留原形式。n 0分支处理空和场景。另外当 $|q|1$ 且 $n\to\infty$ 时 $q^n\to0$前 n 项和收敛到 $\frac{a_1}{1-q}$这个极限在几何分布期望、缓存命中率预估中很常见可以用gp_sum_stable(a1, q, 100000)与极限值对比误差应小于 1e-6。q 的取值范围Sn 的形态代码注意点$q1$$n a_1$独立分支否则除零错误$q1$$\frac{a_1(q^n-1)}{q-1}$用(q**n - 1)/(q - 1)避免符号混乱$0q1$$\frac{a_1(1-q^n)}{1-q}$n 较大时趋近于 $\frac{a_1}{1-q}$$-1q0$正负交替但有界浮点累计误差随 n 增大$q-1$正负震荡且幅度增大幂运算符号按奇偶变化结果不稳定4. 等差与等比的类比三种求和技术选型与典型拆分4.1 类比关系表和差与积商的对应以及对数变换等差数列做加法等比数列做乘法。把两者并排看很多公式可以成对记忆和对应积差对应商系数运算对应指数运算。讲义里的类比表还隐含一个隐藏技巧正项等比数列取对数后变成等差数列因为 $\log(a_n)\log(a_1)(n-1)\log q$形式与等差数列通项完全一致。这个变换在算法分析中很有用比如快速幂递归层数 $T(n)T(n/2)O(1)$ 展开后的调用次数就是一个等比数列取对数后层数就是 $\log_2 n1$。维度等差数列等比数列递推关系$a_{n1}-a_nd$$a_{n1}q a_n$通项形态一次函数 $dnb$指数函数 $a_1 q^{n-1}$中项条件$2bac$$b^2ac$前 n 项和二次函数指数式分段特殊退化$d0$ 为常数列$q1$ 为常数列常用变换差分取对数这组类比还有一个容易忽略的方向等比数列的判定不能只靠比值恒定还要排除首项为 0 的特殊场景等差数列判定没有类似的排除项任何常数公差都能定义。所以写代码做类型判断时等差和等比的判定逻辑不能直接复制同一套模板。理解了这层差异后面三种求和套路的分工就清楚了。4.2 分组求和把通项拆成等差部分与等比部分如果一个数列的通项是等差部分与等比部分的简单叠加比如 $a_kk2^k$那么前 n 项和可以直接拆成 $\sum_{k1}^n k\sum_{k1}^n 2^k$。前一部分用 $\frac{n(n1)}{2}$后一部分用 $2^{n1}-2$。这种拆分依赖求和运算的线性性质和的求和等于求和的和。代码实现时整数运算优先于浮点运算def group_sum(n): # S sum_{k1}^n (k 2^k) sum_part_ap n * (n 1) // 2 sum_part_gp 2 ** (n 1) - 2 # a12, q2 return sum_part_ap sum_part_gp for n in [1, 5, 10, 100]: brute sum(k 2 ** k for k in range(1, n 1)) assert group_sum(n) brutesum_part_gp之所以是2 ** (n 1) - 2来自等比求和公式 $\sum_{k1}^n 2^k2^{n1}-2$首项 2、公比 2。如果公比不是整数再改用上一章的gp_sum_stable。分组求和的关键前提是通项能拆成两个标准数列的和且两部分下标范围一致。遇到 $a_kk\cdot2^k$ 这种乘积形式分组求和不再适用需要切换到错位相减。4.3 裂项求和构造相邻项差让中间项全部抵消裂项求和的核心是把一个通项改写成相邻两项的差求和时中间项成对抵消只剩下首尾。最经典的恒等式是 $\frac{1}{k(k1)}\frac{1}{k}-\frac{1}{k1}$于是 $\sum_{k1}^n\frac{1}{k(k1)}1-\frac{1}{n1}$。讲义还给了分母为两个奇数因式的变式$\frac{1}{(2k-1)(2k1)}\frac{1}{2}\left(\frac{1}{2k-1}-\frac{1}{2k1}\right)$。判断是否该用裂项的快速标准通项是分式分母是两个因式相乘且两因式之差为常数。def telescoping_sum_1(n): # sum 1/(k*(k1)), k1..n return 1.0 - 1.0 / (n 1) def telescoping_sum_2(n): # sum 1/((2k-1)*(2k1)), k1..n return 0.5 * (1.0 - 1.0 / (2 * n 1))第二种写法里裂项后首项是 $\frac{1}{1}$末项是 $\frac{1}{2n1}$系数 $\frac{1}{2}$ 很容易丢。写代码验证时通常保留一个暴力累加函数把 n 从 1 到 1000 全部比较一遍。裂项求和的思想在工程里也有对应如果一段数据能表示成相邻状态的差累积过程就只需要维护当前状态不需要保留全部中间结果这跟滑动窗口维护增量是一个道理。4.4 错位相减处理等差×等比的通项当通项因子是等差数列乘以等比数列例如 $a_kk q^{k-1}$分组与裂项都不适用。此时用错位相减设 $S\sum_{k1}^n k q^{k-1}$两边乘以 $q$ 后与原式相减二次整理得到闭合公式 $S\frac{1-(n1)q^nnq^{n1}}{(1-q)^2}$限制条件 $q\neq1$。这个公式在二叉树路径计数、几何分布期望中经常出现。代码里同时保留公式版和暴力版小规模输入下互相校验def sum_k_qk_formula(n, q): # S sum_{k1}^n k * q^(k-1), q ! 1 if q 1: return n * (n 1) // 2 numerator 1 - (n 1) * (q ** n) n * (q ** (n 1)) return numerator / ((1 - q) ** 2) def sum_k_qk_brute(n, q): return sum(k * (q ** (k - 1)) for k in range(1, n 1)) for n in range(1, 20): for q in [0.5, 2, -1]: assert abs(sum_k_qk_formula(n, q) - sum_k_qk_brute(n, q)) 1e-9numerator的三项分别来自错位相减后的首项、交叉尾项和末项修正$q^n$ 与 $q^{n1}$ 由公式统一管理负公比时也能通过测试。这个公式对 $q1$ 不适用代码里单独返回等差数列求和结果。工程实现时如果 n 很大且 q 接近 1应优先考虑分数形式或高精度库避免浮点误差被二次方项放大。5. 公式落地递推回代、符号计算与取模验算5.1 递推生成前N项回代封闭式拿到公式后第一步不是直接用而是先用递推生成前 N 项回代。递推是定义层的唯一标准封闭公式是推导层的结论两者一致才说明公式没有用错。下面的函数把等差通项、等比通项分别与递推生成结果做近似比较def validate_seq(a1, d, q, n): ap_expected [a1 i * d for i in range(n)] gp_expected [a1 * (q ** i) for i in range(n)] ap_loop, gp_loop [a1], [a1] for i in range(1, n): ap_loop.append(ap_loop[-1] d) gp_loop.append(gp_loop[-1] * q) ap_ok all(abs(x - y) 1e-9 for x, y in zip(ap_expected, ap_loop)) gp_ok all(abs(x - y) 1e-9 for x, y in zip(gp_expected, gp_loop)) return ap_ok, gp_ok等比部分在q为负数且 n 较大时浮点乘积的符号会反复变化abs(x-y)1e-9的容差仍然够用。这个验证函数的参数a1、d、q、n分别对应首项、公差、公比和生成长度放在单元测试里可以快速拦截公式抄错、参数顺序写反这类低级问题。5.2 用SymPy做符号推导校验对需要推导的场景可以用 SymPy 做符号级求和避免手推错位相减时漏项。下面的代码声明符号变量后直接计算两个典型求和并化简from sympy import symbols, summation, factor k, n symbols(k n) s1 summation(k, (k, 1, n)) s2 summation(k * 2 ** (k - 1), (k, 1, n)) print(factor(s1)) # n*(n1)/2 print(factor(s2)) # 2**n*(n-1)1s1输出n*(n1)/2与等差数列求和公式一致s2化简后是 $2^n(n-1)1$可以快速验证第 4 章的错位相减公式。符号计算适合检查通项拆分是否正确但不能替代浮点验证因为符号计算不涉及溢出和精度问题。5.3 取模场景下的等比求和逆元与pow组合算法题里经常要求结果对一个大质数取模等比求和公式不能直接用浮点除法需要把分母 $1-q$ 换成逆元。Python 3.8 之后的内置pow支持负指数求模逆元实现如下def gp_sum_mod(a1, q, n, mod): # 等比数列前 n 项和取模, q ! 1 if q 1: return (a1 % mod) * n % mod num (pow(q, n, mod) - 1) % mod den_inv pow(q - 1, -1, mod) # Python 3.8 支持模逆元 return (a1 % mod) * num % mod * den_inv % modpow(q, n, mod)是快速幂取模时间复杂度 O(log n)pow(q - 1, -1, mod)返回q-1在模mod下的逆元。使用前提是mod为素数且q-1与mod互质。若q 1走独立分支返回a1 * n % mod此时不存在分母不需要逆元。调用时注意a1也要取模后再参与乘法避免 Python 大整数在mod较小时拖慢速度。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进