<—点个赞吧QwQ
宣传一下算法提高课整理{:target=”_blank”}
在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链,在项链上有 $N$ 颗能量珠。
能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数。
并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记。
因为只有这样,通过吸盘(吸盘是 Mars 人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量。
如果前一颗能量珠的头标记为 $m$,尾标记为 $r$,后一颗能量珠的头标记为 $r$,尾标记为 $n$,则聚合后释放的能量为 $m \\times r \\times n$(Mars 单位),新产生的珠子的头标记为 $m$,尾标记为 $n$。
需要时,Mars 人就用吸盘夹住相邻的两颗珠子,通过聚合得到能量,直到项链上只剩下一颗珠子为止。
显然,不同的聚合顺序得到的总能量是不同的,请你设计一个聚合顺序,使一串项链释放出的总能量最大。
例如:设 $N=4$,$4$ 颗珠子的头标记与尾标记依次为 $(2,3) (3,5) (5,10) (10,2)$。
我们用记号 $⊕$ 表示两颗珠子的聚合操作,$(j⊕k)$ 表示第 $j$,$k$ 两颗珠子聚合后所释放的能量。则
第 $4、1$ 两颗珠子聚合后释放的能量为:$(4⊕1)=10 \\times 2 \\times 3=60$。
这一串项链可以得到最优值的一个聚合顺序所释放的总能量为 $((4 \\oplus 1) \\oplus 2) \\oplus 3) = 10 \\times 2 \\times 3+10 \\times 3 \\times 5+10 \\times 5 \\times 10=710$。
输入格式
输入的第一行是一个正整数 $N$,表示项链上珠子的个数。
第二行是 $N$ 个用空格隔开的正整数,所有的数均不超过 $1000$,第 $i$ 个数为第 $i$ 颗珠子的头标记,当 $i<N$ 时,第 $i$ 颗珠子的尾标记应该等于第 $i+1$ 颗珠子的头标记,第 $N$ 颗珠子的尾标记应该等于第 $1$ 颗珠子的头标记。
至于珠子的顺序,你可以这样确定:将项链放到桌面上,不要出现交叉,随意指定第一颗珠子,然后按顺时针方向确定其他珠子的顺序。
输出格式
输出只有一行,是一个正整数 $E$,为一个最优聚合顺序所释放的总能量。
数据范围
$4 \\le N \\le 100$,
$1 \\le E \\le 2.1 \\times 10^9$
输入样例:
4
2 3 5 10
输出样例:
710
思路
这题我们可以用类似环形石子合并拆环。
闫氏$\text{DP}$分析法:
状态表示:$f_{l,r}$
- 集合:把第$l$个数到第$r$个数合并成一串的最大能量
- 属性:$\max$
状态计算
- 如果用$l + 1$为分割点来合并两个部分,能量就是$f_{l,l + 1} + f_{l + 1,r} + a_l * a_{l + 1} * a_{r}$
- 如果用$l + 2$为分割点来合并两个部分,能量就是$f_{l,l + 2} + f_{l + 2,r} + a_l * a_{l + 2} * a_{r}$
- 如果用$k$为分割点来合并两个部分,能量就是$f_{l,k} + f_{k,r} + a_l * a_k * a_{r}$
- 所以状态转移方程就是$f_{l,r}=\underset{l + 1 \le k \le r - 1}\max\lbrace f_{l,k} + f_{k,r} + a_l * a_k * a_r \rbrace$
初始状态:$f_{i,i + 1}(1 \le i \le 2 \times n - 1)$
目标状态:$\underset{1 \le i \le n}\max f_{i,i + n}$
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 210;
int n;
int a[N];
LL f[N][N];
int main () {
cin >> n;
for (int i = 1;i <= n;i++) {
cin >> a[i];
a[i + n] = a[i];
}
for (int len = 3;len <= 2 * n;len++) {
for (int l = 1;l + len - 1 <= 2 * n;l++) {
int r = l + len - 1;
for (int k = l + 1;k <= r - 1;k++) f[l][r] = max (f[l][r],f[l][k] + f[k][r] + a[l] * a[k] * a[r]);
}
}
LL ans = 0;
for (int i = 1;i <= n;i++) ans = max (ans,f[i][i + n]);
cout << ans << endl;
return 0;
}
把点对转换成2 3 5 10 2我感觉自己做的话 想不到这样转
这叫断环成链,有环的问题很多可以这么转化成现行的问题
我说的是(2,3)的点对 变成2 3 或者更直接点 我会想不到 后面再加一个和开头相等的2
为什么这里的len可以是2n呢
按模拟来的话 n+1就足够了 2n的话 为什么也能AC
因为我懒