原题链接:能量项链
解题思路:
处理环形结构:将环形项链"展开"成线性结构,通过复制一份数组来处理
将长度为N的环形数组复制一份,形成长度为2N的线性数组
这样,任何长度为N的连续子数组都可以表示原始环形结构中的一种可能情况
例如,[1,2,3,4] → [1,2,3,4,1,2,3,4],子数组[3,4,1,2]就是原环形数组的一种可能表示
定义状态:dp[i][j] 表示将区间[i,j]的珠子合并成一颗珠子所能释放的最大能量
当合并两个子区间[i,k]和[k+1,j]时,释放的能量计算如下:
a[i]:区间起始珠子的头标记(合并后新珠子的头标记)
a[k+1]:分割点后一颗珠子的头标记(也是前一区间最后一颗珠子的尾标记)
a[j+1]:区间结束后一颗珠子的头标记(也是当前区间最后一颗珠子的尾标记)
状态转移:尝试所有可能的分割点,找出最优合并方式
结果:考虑所有可能的长度为N的连续区间,取最大值
参考代码:
#include <bits/stdc++.h>
#define INF 0x3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pr;
const int N = 1e5 + 10;
ll n;
int main() {
int N;
cin >> N; // 读取珠子的数量
// 读取每个珠子的头标记(1-indexed)
vector<int> values(N + 1);
for (int i = 1; i <= N; i++) {
cin >> values[i];
}
// 为了处理环形结构,我们将数组复制一份
// 这样可以处理任意连续的N个珠子,包括跨越原始首尾的情况
vector<int> a(2 * N + 1);
for (int i = 1; i <= N; i++) {
a[i] = values[i]; // 原始数组
a[i + N] = values[i]; // 复制的数组
}
// dp[i][j]表示将区间[i,j]合并成一颗珠子所能释放的最大能量
vector<vector<int>> dp(2 * N + 1, vector<int>(2 * N + 1, 0));
// 枚举区间长度,从2开始(至少需要两颗珠子才能合并)
for (int len = 2; len <= N; len++) {
// 枚举起始位置
for (int i = 1; i <= 2 * N - len + 1; i++) {
int j = i + len - 1; // 计算终止位置
// 枚举分割点k,尝试所有可能的合并方式
for (int k = i; k < j; k++) {
// 计算合并两个子区间后释放的能量
// a[i]:左区间第一颗珠子的头标记
// a[k+1]:右区间第一颗珠子的头标记(也是左区间最后一颗珠子的尾标记)
// a[j+1]:右区间最后一颗珠子的尾标记(也是下一颗珠子的头标记)
int energy = a[i] * a[k + 1] * a[j + 1];
// 状态转移:尝试更新dp[i][j]
// dp[i][k]:左区间[i,k]的最大能量
// dp[k+1][j]:右区间[k+1,j]的最大能量
// energy:合并这两个区间释放的能量
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + energy);
}
}
}
// 找出所有可能的起始位置中的最大值
// 由于项链是环形的,我们需要考虑所有可能的"断开点"
int maxEnergy = 0;
for (int i = 1; i <= N; i++) {
// dp[i][i+N-1]表示从位置i开始,连续N个珠子(即整个项链)的最大能量
maxEnergy = max(maxEnergy, dp[i][i + N - 1]);
}
cout << maxEnergy << endl;
return 0;
}0.0分
0 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复