P4481 [BJWC2018] 序列合并
算法
动态规划.
思路
区间dp, 我们令 \(g_{l,r}\) 为将 \(l-r\) 这一段序列合并成一个点的答案, \(f_{l,r,i}\) 表示将 \(l - r\) 这一段分成 \(i\) 段分别合并的最小花费.
对于数组 \(g\) 的转移, 我们枚举分了多少段, 而对于 \(f\), 我们枚举转移的最后一段即可.
\(f\) 数组可以滚动优化掉一维.
时间复杂度 \(\mathcal{O}(n^4)\).
#include "iostream"
#include "cstring"
using namespace std;
const int N = 3e2 + 10;
int n, L, R;
int a[N], sum[N];
inline void init()
{
cin >> n >> L >> R;
for (int i = 1; i <= n; ++i)
cin >> a[i],
sum[i] = sum[i - 1] + a[i];
return;
}
int f[N][N], g[N][N];
inline void calculate()
{
memset(g, 0x3f, sizeof g);
for (int i = 1; i <= n; ++i)
g[i][i] = 0;
for (int l = n; l >= 1; --l)
{
memset(f, 0x3f, sizeof f);
f[l - 1][0] = 0;
for (int r = l; r <= n; ++r)
{
for (int i = 1; i <= r - l + 1 and i <= R; ++i)
for (int p = r; p >= l; --p)
f[r][i] = min(f[r][i], f[p - 1][i - 1] + g[p][r]);
for (int i = L; i <= R; ++i)
g[l][r] = min(g[l][r], f[r][i] + sum[r] - sum[l - 1]);
f[r][1] = min(f[r][1], g[l][r]);
}
}
cout << (g[1][n] == 0x3f3f3f3f ? 0 : g[1][n]) << '\n';
return;
}
inline void solve()
{
init();
calculate();
return;
}
int main()
{
int T;
cin >> T;
while (T--)
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现