1 条题解
-
0
题目分析
本题要求通过给定的 块砖(按顺序给出长度 ),按照特定规则构建一个砖墙,使得墙的“美丽度”(即被四个砖块共顶点的顶点个数)最大。
关键观察
. 砖墙构建规则:
第 行:从左到右放置砖块
第 行:从右到左放置砖块,右端对齐
第 行:从左到右放置砖块,左端对齐
以此类推,方向交替,且相邻行首尾对齐
. 美丽度的含义:
一个顶点被四个砖块共享,意味着在二维平面上,该点是两个垂直砖缝的交点:
垂直砖缝:两行之间的分隔
水平砖缝:同行内两块砖之间的接缝
. 问题的转化:
实际上,美丽度等于层数减一(即行数减一),因为每相邻两行之间最多只能有一个共享顶点。问题转化为:如何划分砖块序列,使得形成的层数最多。
. 约束条件:
每层由若干连续的砖块组成。设第 层包含砖块 ,其总长度为 。根据构建规则:
奇数层(从左到右):(与上一层总长度相等)
偶数层(从右到左):(与上一层总长度相等)
因此,相邻层的总长度必须相等。
算法思路
. 动态规划定义:
定义 表示考虑到第 块砖,最后一段(当前层)以第 块砖结束时,能获得的最大美丽度(层数)。
. 状态转移:
设当前层为 ,总长度为 。
要找前一层 ,使得其总长度也等于 。
转移方程:

其中 是满足 的最大下标。
. 预处理优化:
为了快速找到这样的 ,我们需要预处理:
pos[i][j]:对于区间 ,找到最大的 使得 的总长度等于 的总长度
g[i][j]:区间 内有多少个前缀和等于某个后缀和(用于辅助计算)
. 实际实现技巧:
代码中使用了二维 DP 数组,但实际有效的状态是 其中 。通过维护 pos 数组和 g 数组,可以高效地进行转移。
算法步骤
. 输入处理:
读取 和砖块长度数组 。
. 三重循环计算:
外层循环: 从 到 ,表示当前考虑的前一层结束位置 中层循环: 从 到 ,表示当前层结束位置 内层循环:通过指针 查找满足长度相等的更早的层
. 状态转移细节:
初始化
计算当前层 的总长度
找到 使得 的总长度等于
如果找到匹配的 ,尝试转移:$dp[i][j] = \max(dp[i][j], dp[p][i-1] + g[i][j-1] + 1)$
同时考虑不开始新层的情况:
. 输出结果:
最终答案为 ,即考虑所有砖块时的最大层数减一(美丽度)。
时间复杂度
时间复杂度:,因为有三重循环,但内层指针 是单调移动的,均摊
空间复杂度:,用于存储 、、 数组
对于 , 在合理范围内。
正确性证明
. 问题等价性:
美丽度等于层数减一,因此最大化美丽度等价于最大化层数。
. 长度相等约束:
由于砖墙的构建规则要求相邻层总长度相等,否则无法对齐边缘。
. 动态规划的最优子结构:
最优解的最后几层必然也是最优的。如果 作为最后一层,那么前面部分 必须划分成若干层,且倒数第二层长度必须等于 的长度。
. 转移的完备性:
通过枚举所有可能的 组合,并利用 pos 数组快速找到匹配的前一层,确保考虑了所有可能的划分方式。
代码实现详解
#include <bits/stdc++.h> using namespace std; const int N = 5e3 + 5; int a[N], dp[N][N], g[N][N], pos[N][N]; int main() { int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; // 动态规划计算 for (int i = 1; i <= n; i++) { int sum = 0; // 当前层[i,j]的总长度 int pre = 0; // 前一层[p+1,i-1]的总长度 int p = i - 1; // 指针,向左移动 for (int j = i; j <= n; j++) { // 初始化 dp[i][j] = dp[i-1][i-1]; g[i][j] = g[i][j-1]; sum += a[j]; // 移动p指针,使pre接近sum while (p > 0 && pre + a[p] <= sum) { pre += a[p]; p--; } // 如果找到长度相等的层 if (sum == pre) { g[i][j]++; // 增加匹配计数 } pos[i][j] = p; // 记录位置 // 状态转移 if (pos[i][j-1] > 0) { // 使用[i,j-1]作为最后一层,尝试转移 dp[i][j] = max(dp[i][j], dp[pos[i][j-1]][i-1] + g[i][j-1]); } // 考虑不选当前砖块的情况 dp[i][j] = max(dp[i][j], dp[i][j-1]); dp[i][j] = max(dp[i][j], dp[i-1][j]); } } cout << dp[n][n] << endl; return 0; }
- 1
信息
- ID
- 5969
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 1
- 上传者