P4481 [BJWC2018] 序列合并

题目链接

算法

动态规划.

思路

区间dp, 我们令 \(g_{l,r}\) 为将 \(l-r\) 这一段序列合并成一个点的答案, \(f_{l,r,i}\) 表示将 \(l - r\) 这一段分成 \(i\) 段分别合并的最小花费.

对于数组 \(g\) 的转移, 我们枚举分了多少段, 而对于 \(f\), 我们枚举转移的最后一段即可.

\(f\) 数组可以滚动优化掉一维.

时间复杂度 \(\mathcal{O}(n^4)\).

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
#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; }
posted @   Steven1013  阅读(5)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开