区间dp思想
删数
链接:https://www.luogu.com.cn/problem/P2426
题目描述
有
每次操作都有一个操作价值,比如现在要删除从
问如何操作可以得到最大值,求操作的最大价值。
输入格式
第一行为一个正整数
第二行有
输出格式
一行,包含一个正整数,为操作的最大值
样例 #1
样例输入 #1
6
54 29 196 21 133 118
样例输出 #1
768
提示
【样例解释和说明】
说明,经过
【数据范围】
解答
取巧做法
- 因为一次可以删除前面任意个数和后面任意个数,转换为区间 dp
- 最终都会是只删除前和后,区间两端,和区间 dp 异曲同工之妙
- 唯一难受的是既要删除后面,又要删除前面情况,不好讨论
- 转换为只用删前面,会存在最优解,因为删后面和前面算法一样,值一样,删除的区间 + 前面删除的区间 == 考虑全从前面删,区间 dp 思想考虑这个问题
- 所以
f[i]
定义为删除到i
的最优解
#include <iostream>
using namespace std;
const int N = 1010;
int a[N];
int f[N];
int n;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++)
{
f[i] = a[i] + f[i - 1];
for (int j = 1; j < i; j++)
f[i] = max(f[i], f[j - 1] + (i - j + 1) * abs(a[i] - a[j]));
}
cout << f[n];
return 0;
}
中规中矩做法
- 区间 dp
f[i][j]
:表示删除i~j
之间数的方案数,价值最优值- 第三层循环即是
i~j
之间枚举中间点 - 两次三层循环是因为考虑删除前面和后面数两种情况
#include <iostream>
using namespace std;
const int N = 110;
int a[N];
int f[N][N];
int n;
int t(int i, int j)
{
if (i == j) return a[i];
else return abs(a[i] - a[j]) * abs(j - i + 1);
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
{
for (int k = i; k <= j; k++)
f[i][j] = max(f[k + 1][j] + t(i, k), f[i][j]);
for (int k = i; k <= j; k++)
f[i][j] = max(f[i][k] + t(k + 1, j), f[i][j]);
}
printf("%d", f[1][n]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】