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;
}
posted @   Steven1013  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示