NC50493 石子合并
题目
题目描述
将n堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。
请编写一个程序,读入堆数n及每堆的石子数,并进行如下计算:
- 选择一种合并石子的方案,使得做n-1次合并得分总和最大。
- 选择一种合并石子的方案,使得做n-1次合并得分总和最小。
输入描述
输入第一行一个整数n,表示有n堆石子。
第二行n个整数,表示每堆石子的数量。
输出描述
第一行为合并得分总和最小值,
第二行为合并得分总和最大值。
示例1
输入
4 4 5 9 4
输出
43 54
备注
对于 的数据,有 。
题解
知识点:区间dp。
普通的石子合并用区间dp直接能做,但这里是环形的,有两种处理方式,比较简单的是复制一段接在后面,就可以做了。
如果是线性dp的环形处理可以做两次dp,一次是强制断开的情况,一次是强制链接的情况。
可以用前缀和优化求和。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; int sum[407], dp[407][407];///循环,端点开大一倍 int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; for (int i = 1;i <= n;i++) cin >> sum[i], sum[i + n] = sum[i]; for (int i = 1;i <= 2 * n;i++) sum[i] += sum[i - 1]; memset(dp, 0x3f, sizeof(dp)); for (int i = 1;i <= 2 * n;i++) dp[i][i] = 0; for (int l = 2;l <= n;l++) {///算到长度为n for (int i = 1;i <= 2 * n;i++) {///搞循环,因为分割区间可能到加长的区间,因此大于n的区间也要算 int j = i + l - 1; for (int k = i;k < j;k++) dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]); } } int ans = ~(1 << 31); for (int i = 1;i <= n;i++) ans = min(ans, dp[i][i + n - 1]); cout << ans << '\n'; memset(dp, 0, sizeof(dp)); for (int l = 2;l <= n;l++) { for (int i = 1;i <= 2 * n;i++) {///搞循环 int j = i + l - 1; for (int k = i;k < j;k++) dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]); } } ans = 0; for (int i = 1;i <= n;i++) ans = max(ans, dp[i][i + n - 1]); cout << ans << '\n'; return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16586913.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧