小明在玩一个消除游戏。这个消除游戏有点特别。游戏中,你会得到 n 个一维排列的有各自颜色的砖块。
消除的时候,你有三种消除方案。你可以单消一个砖块,这样你可以得到 a 的得分;如果两个颜色一样的砖块在一起,你可以将这两个砖块一起消除获得 b 的得分;如果三个颜色一样的砖块在一期,你可以将这三个砖块一起消除获得 c 的得分。
消除后,被消除的砖块自动消失,被消除砖块的左右两端的砖块将在消除之后挨在一起。
小明想知道在最优策略下他能得到多少得分。
第一行4个整数n,a,b,c,表示砖块数量,和一消/二消/三消的得分。
接下来一行个整数,第
个整数
表示第
个砖块的颜色。
输出最高得分
8 1 3 7 3 1 3 1 3 2 2 3
14
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, a, b, c;
cin >> n >> a >> b >> c;
vector<int> s(n);
for (int i = 0; i < n; ++i) {
cin >> s[i];
}
// 预处理每个位置j前面相同颜色的位置(升序存储)
vector<vector<int>> prev(n);
for (int j = 0; j < n; ++j) {
for (int i = 0; i < j; ++i) {
if (s[i] == s[j]) {
prev[j].push_back(i);
}
}
}
// 初始化DP数组
vector<vector<int>> dp(n, vector<int>(n, 0));
for (int i = 0; i < n; ++i) {
dp[i][i] = a; // 单个砖块只能单消
}
// 区间DP,按区间长度从小到大计算
for (int len = 2; len <= n; ++len) {
for (int i = 0; i + len <= n; ++i) {
int j = i + len - 1;
dp[i][j] = 0;
// 情况1:分割成两个子区间
for (int k = i; k < j; ++k) {
dp[i][j] = max(dp[i][j], dp[i][k] + dp[k+1][j]);
}
// 情况2:单消最后一个砖块
dp[i][j] = max(dp[i][j], dp[i][j-1] + a);
// 情况3:寻找同色砖块,处理双消或三消
for (int k : prev[j]) {
if (k < i) continue; // k必须在[i, j-1]范围内
// 双消:k和j
int current = 0;
if (k > i) current += dp[i][k-1];
if (k+1 <= j-1) current += dp[k+1][j-1];
current += b;
dp[i][j] = max(dp[i][j], current);
// 三消:寻找k前面的同色m,形成m、k、j三消
for (int m : prev[k]) {
if (m < i) continue;
int temp = 0;
if (m > i) temp += dp[i][m-1];
if (m+1 <= k-1) temp += dp[m+1][k-1];
if (k+1 <= j-1) temp += dp[k+1][j-1];
temp += c;
dp[i][j] = max(dp[i][j], temp);
}
}
}
}
cout << dp[0][n-1] << endl;
return 0;
} import java.util.Scanner;
// DP[i][j]:单消、双消、三消
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int a = in.nextInt(), b = in.nextInt(), c = in.nextInt();
int[] s = new int[n];
for (int i = 0; i < n; i++) {
s[i] = in.nextInt();
}
int[][] dp = new int[n][n];
for (int len = 1; len <= n; len++) {
for (int i = 0; i + len - 1 < n; i++) {
int j = i + len - 1, res = 0;
// 单消:枚举s[k]
for (int k = i; k <= j; k++) {
int l = (i <= k - 1) ? dp[i][k - 1] : 0; // s[i]还在
int r = (k + 1 <= j) ? dp[k + 1][j] : 0;
res = Math.max(res, a + l + r);
}
// 双消:枚举s[k]和s[i]匹配
for (int k = i + 1; k <= j; k++) {
if (s[k] != s[i]) continue;
int l = (i + 1 <= k - 1) ? dp[i + 1][k - 1] : 0; // s[i]没了
int r = (k + 1 <= j) ? dp[k + 1][j] : 0;
res = Math.max(res, b + l + r);
}
// 三消:枚举s[k]、s[t]和s[i]匹配
for (int k = i + 1; k < j; k++) {
if (s[k] != s[i]) continue;
for (int t = k + 1; t <= j; t++) {
if (s[t] != s[i]) continue;
int l = (i + 1 <= k - 1) ? dp[i + 1][k - 1] : 0;
int m = (k + 1 <= t - 1) ? dp[k + 1][t - 1] : 0;
int r = (t + 1 <= j) ? dp[t + 1][j] : 0;
res = Math.max(res, c + l + m + r);
}
}
dp[i][j] = res;
}
}
System.out.println(dp[0][n - 1]);
}
}