NOIP 2006 能量项链

原题

思路

简单的区间 dp , 显然 \(dp[i][j]\) 表示从 \(i\) 一直聚合到 \(j\) .
再枚举断点 \(k(1\leq k < j)\) , 考虑合并 \(dp[i][k]\)\(dp[k + 1][j]\) , 显然最终答案里包含 \(dp[i][k] + dp[k + 1][j]\).
\(a[i][0]\) 表示 \(i\) 的头标记, \(a[i][1]\) 表示 \(i\) 的尾标记.
再考虑聚合后的额外收益为 \(m \times r \times n\)\(a[i][0] \times a[k][1] \times a[j][1]\)
综上得 \(dp[i][j] = \mathop{max\{dp[i][k] + dp[k + 1][j] + a[i][0] \times a[k][1] \times a[j][1]\}}\limits_{1 \leq k < j}\)

注意:

  1. 初始时有 \(dp[i][i] = 0(1 \leq i \leq 2n)\)
  2. 破环为链

代码

剩下的看代码吧:

#include <bits/stdc++.h>
#define int long long
using namespace std;

inline int read() {
    int x = 0; char c = getchar(); bool f = 1;
    while(c < '0' || c > '9') { if(c == '-') f = 0; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return (f ? x : -x);
}

const int N = 1e3 + 10;
int n, res, a[N][2], dp[N][N];

signed main() {
    n = read();
    for(int i = 1; i <= n; ++i) {
        a[i - 1][1] = a[i][0] = read();
        if(i == n) a[i][1] = a[1][0];
    }
    for(int i = 1; i <= n; ++i) { 
        a[i + n][0] = a[i][0];
        a[i + n][1] = a[i][1];
    }

    for(int l = 1; l < n; ++l) {
        for(int i = 1; i <= (n << 1); ++i) {
            int j = i + l;

            for(int k = i; k < j; ++k) {
                dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + a[i][0] * a[k][1] * a[j][1]);
            }

            res = max(res, dp[i][j]);
        }
    }

    printf("%lld\n", res);

    return 0;
}
posted @ 2022-05-16 11:43  聂天泽  阅读(15)  评论(0编辑  收藏  举报