『数组的最大代价 贪心优化DP』
<更新提示>
<第一次更新>
<正文>
数组的最大代价(51nod 1270)#
Description#
数组A包含N个元素A1, A2......AN。数组B包含N个元素B1, B2......BN。并且数组A中的每一个元素Ai,都满足1 <= Ai <= Bi。数组A的代价定义如下:
S=N∑i=2|Ai−Ai−1|
(公式表示所有两个相邻元素的差的绝对值之和)
给出数组B,计算可能的最大代价S。
Input Format#
第1行:1个数N,表示数组的长度(1 <= N <= 50000)。
第2 - N+1行:每行1个数,对应数组元素Bi(1 <= Bi <= 10000)。
Output Format#
输出最大代价S。
Sample Input#
5
10
1
10
1
10
Sample Output#
36
解析#
化简题目大意可以得知:即求一个数组限制下的相邻两项最大差值和。
有一个很简单的暴力DP思路如下:
设f[i][j]代表前i项当中,第i个数字取j的最大和。
f[i][j]=max{f[i−1][k]+|j−k|}
(i=1−n,j=1−Bi,k=1−Bi−1)
时间复杂度O(nMax{bi}2)
不怕暴力TLE,就怕暴力不敢想。没错,最简单的暴力就是这道题的关键。
我们可以用贪心对这个暴力进行降维打击优化。
最显然的贪心,构造Ai时极端化能得到全局最优解。即:Ai的最优取值方案只有两种可能,1或Bi,这样可以让相邻两项的差的绝对值尽可能大。
那么j,k都只能取最大值或1,直接实现O(1)转移。可以优化一下状态:设f[i][0/1]代表前i项当中,第i个数字取1(第二维为0)或Bi(第二维为1)的最大和。
状态转移方程:
f[i][0]=max(f[i−1][0],f[i−1][1]+|Bi−1−1|)f[i][1]=max(f[i−1][0]+|Bi−1|,f[i−1][1]+|Bi−Bi−1|)
可以滚动数组一下把第一维的空间也优化了。
Code:
#include<bits/stdc++.h>
using namespace std;
inline void read(int &k)
{
int w=0,x=0;char ch;
while(!isdigit(ch))w|=ch=='-',ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
k=(w?-x:x);return;
}
const int N=50000+80;
int n,b[N],f[2][2];
inline void input(void)
{
read(n);
for(int i=1;i<=n;i++)read(b[i]);
}
inline void dp(void)
{
f[1][0]=f[1][1]=0;
for(int i=2;i<=n;i++)
{
f[i&1][0]=max(f[i-1&1][0],f[i-1&1][1]+abs(b[i-1]-1));
f[i&1][1]=max(f[i-1&1][0]+abs(b[i]-1),f[i-1&1][1]+abs(b[i]-b[i-1]));
}
}
int main(void)
{
input();
dp();
printf("%d\n",max(f[n&1][0],f[n&1][1]));
}
考点:算法思想的结合运用。
<后记>
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步