能量项链

能量项链链2)

题目描述

在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链。在项链上有 NN 颗能量珠。能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。因为只有这样,通过吸盘(吸盘是 Mars 人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。如果前一颗能量珠的头标记为 mm,尾标记为 rr,后一颗能量珠的头标记为 rr,尾标记为 nn,则聚合后释放的能量为 m×r×nm \times r \times n(Mars 单位),新产生的珠子的头标记为 mm,尾标记为 nn

需要时,Mars 人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。

例如:设 N=4N=444 颗珠子的头标记与尾标记依次为 (2,3)(3,5)(5,10)(10,2)(2,3)(3,5)(5,10)(10,2)。我们用记号 \oplus 表示两颗珠子的聚合操作,(jk)(j \oplus k) 表示第 j,kj,k 两颗珠子聚合后所释放的能量。则第 4411 两颗珠子聚合后释放的能量为:

(41)=10×2×3=60(4 \oplus 1)=10 \times 2 \times 3=60

这一串项链可以得到最优值的一个聚合顺序所释放的总能量为:

(((41)2)3)=10×2×3+10×3×5+10×5×10=710(((4 \oplus 1) \oplus 2) \oplus 3)=10 \times 2 \times 3+10 \times 3 \times 5+10 \times 5 \times 10=710

输入格式

第一行是一个正整数 NN4N1004 \le N \le 100),表示项链上珠子的个数。第二行是 NN 个用空格隔开的正整数,所有的数均不超过 10001000。第 ii 个数为第 ii 颗珠子的头标记(1iN1 \le i \le N),当 i<Ni<N 时,第 ii 颗珠子的尾标记应该等于第 i+1i+1 颗珠子的头标记。第 NN 颗珠子的尾标记应该等于第 11 颗珠子的头标记。

至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。

输出格式

一个正整数 EEE2.1×109E\le 2.1 \times 10^9),为一个最优聚合顺序所释放的总能量。

样例输入

4
2 3 5 10

样例输出

710

提示

NOIP 2006 提高组 第一题

思路

其实本题的思路与 环形石子合并 基本相同,都是 化曲为直

对于题目的新定义,其实质是矩阵乘法

矩阵乘法:

设矩阵 A=(aij)m×nA=(a_{ij})_{m\times n}B=(bij)n×sB=(b_{ij})_{n\times s} , 令 C=(cij)m×sC=(c_{ij})_{m\times s}

其中 cij=k=1naikbkj(1im, 1js)c_{ij}=\sum_{k=1}^n{a_{ik}b_{kj}}(1\leq i\leq m,\ 1\leq j\leq s) , 那么矩阵 CC 称为矩阵 AABB 的乘积,记为 C=ABC=ABC=ABC=AB

为方便,称被乘数 AA 为左矩阵,乘数 BB 为右矩阵。

注意事项:

· 只有左矩阵的列数与右矩阵的行数相同的两个矩阵才能相乘。

· 乘积矩阵第 ii 行第 jj 列处的元素等于左矩阵的第 ii 行与右矩阵的第 jj 列对应元素乘积之和,即 (AB)ij=k=1naikbkj(AB)_{ij}=\sum_{k=1}^n{a_{ik}b_{kj}}

· 乘积矩阵的行数等于左矩阵的行数,列数等于右矩阵的列数。

定义 dpi jdp_{i\ j} 为将区间 [i, j][i,\ j] 的能量珠聚合的最大能量。

则可将 [i, j][i,\ j] 区间通过一个分割点 kk 分为两个部分,问题转化为先合并分割点两端的小区间内的能量珠,进而将两个大的能量珠聚合。

因此,可以通过枚举 k (k[i, j))k\ (k \in [i,\ j))

状态转移方程:

dpi j=maxk[i, j1]{dpi k+dpk+1 j+headvl×tailvk×tailvr}dp_{i\ j} = \mathop{max}\limits_{k\in[i,\ j-1]}\{dp_{i\ k} + dp_{k+1\ j} + head_{v_l}\times tail _{v_k}\times tail_{v_r}\}

void solve()
{
    int n;  cin >> n;
    vector<int> a(n + 1);
    vector<pair<int, int>> v(2 * n + 1);
    for (int i=1;i<=n;i++)    cin >> a[i];
    for (int i=1;i<=n;i++)
        v[i] = v[i + n] = {a[i], a[i % n + 1]};

    vector<vector<int>> dp(2 * n + 1, vector<int>(2 * n + 1));
    auto work = [&](auto self, int l, int r) -> int
    {
        if (r - l + 1 == 1) return 0;
        if (dp[l][r])   return dp[l][r];

        for (int i=l;i<r;i++)
            dp[l][r] = max(dp[l][r], self(self, l, i) + self(self, i + 1, r) + v[l].first * v[i].second * v[r].second);
        return dp[l][r];
    };

    int ans = 0;
    for (int i=1;i<=n;i++)
        ans = max(ans, work(work, i, i + n - 1));
    cout << ans;
}

能量项链
http://linyisu.github.io/2025/02/10/题解/能量项链/
作者
linyisu
发布于
2025年2月10日
许可协议