ARTICLE · 1115824
数组划分问题|GESP 六级真题深度解析
2026年09月这次六级编程题从难度到考察知识点范围都比较正常,今天主要介绍下数组划分这个题目解题思路,跟之前的真题“划分字符串”和“计算得分”相似解题思路,详细过程如下:
➡️ 题目大意:
给定一个长度为 n 的整数序列,我们可以将序列切割成若干段连续子序列。
对每一段计算:该段元素和的平方。
求:所有分段平方和的最小值。
数据范围:n ≤ 2000,允许 O(n²) 算法。
➡️ 解题切入点:为什么这道题是「划分DP」?
拿到题目先观察特征:
- 问题针对整条序列操作
- 可以任意位置切割,分成多段
- 每一段独立算分,最后总分累加求最值
完全符合经典模型:序列划分 DP
✅ 固定解题流程:切序列 → 分段算分 → 枚举所有切割方案 → 取全局最优值
➡️ 推导 DP 状态与转移
1. 设计状态
我们定义:
dp[i]:前 i 个元素完成划分后,能得到的最小总平方和
最终答案:dp[n]
2. 思考如何转移(核心:枚举最后一段)
DP 的核心思维:想求前 i 个的最优解,只需要枚举「最后一段从哪里开始」。
假设:
前 i 个元素,最后一刀切在 j 的位置
前半段:1~j,已经是最优划分,代价为 dp[j]
后半段:j+1~i,单独作为最后一段,代价为「区间和的平方」
所以总代价 = 前 j 个最优解 + 最后一段代价
3. 快速求区间和:前缀和优化
设前缀和数组 s[i] 表示前 i 个元素的和:
s[0] = 0,
s[i] = a[1] + a[2] + … + a[i]
则区间 [j+1, i] 的和为:s[i] - s[j]
该段代价:(s[i] - s[j])²
4. 推出最终转移方程
枚举所有合法切割点 j(0 ≤ j < i):
dp[i] = min( dp[j] + (s[i] - s[j])² )
5. 边界条件
dp[0] = 0:0 个元素,代价为 0
其余 dp[i] 初始化为无穷大,表示初始无解,后续不断更新最优值。
➡️ 算法复杂度分析
- 外层循环:枚举 i(1~n)
- 内层循环:枚举切割点 j(0~i-1)
总复杂度:O(n²)
n=2000 时,总运算量约 400 万,完全可以通过,无需斜率优化。
✅ 完整 AC 代码
#include<bits/stdc++.h>using namespace std;typedef long long ll;const int N = 2005;ll a[N], s[N], dp[N];intmain(){int n;cin >> n;// 1. 读入数据 + 预处理前缀和s[0] = 0;for(int i = 1; i <= n; i++){cin >> a[i];s[i] = s[i - 1] + a[i];}// 2. DP数组初始化:无穷大for(int i = 1; i <= n; i++)dp[i] = 1e18;dp[0] = 0; // 边界:0个元素代价为0// 3. 划分DP核心:切序列、算分段代价、求最值for(int i = 1; i <= n; i++){// 枚举所有切割点 jfor(int j = 0; j < i; j++){ll cost = (s[i] - s[j]) * (s[i] - s[j]);dp[i] = min(dp[i], dp[j] + cost);}}cout << dp[n] << endl;return 0;}
✅ 易错点总结
必须开 long long:区间和平方极易爆 int,不开 long long 必错
初始化不能为 0:dp 数组除 dp[0] 外必须初始无穷大
只能连续划分:划分 DP 只能切连续段,不能打乱顺序
j 从 0 开始:j=0 代表前 i 个整体不切割,单独一段
大家好,我是信奥编程刘老师,后续将持续更新C++知识点、备考干货与真题技巧等,如果我的内容对你有帮助,欢迎发给身边有需要的朋友~
..............................................................
大厂技术专家转型青少年编程教练
专注线上1对1教学,带孩子探索奇妙编程
有编程学习考级相关问题,欢迎交流