代码源每日一题 709. 最大权值划分
#709. 最大权值划分
题目描述
对于一段序列,定义这段序列的权值为这段序列的极差,即序列的最大值与最小值之差。
给定一个序列 \(a\) ,你可以将它划分成任意段连续的序列,求出每一段的权值和的最大值
输入格式
第一行输入一个整数 \(n\) , 表示序列的长度 \((1≤n≤10^6)\)。
第二行输入 \(n\) 个整数 \(a_1,a_2,a_3,…,a_n\) 表示给定的序列 。\((−10^9≤a_i≤10^9)\)
输出格式
输出一行一个整数表示每一段的权值和的最大值。
样例输入
5
9 6 1 8 8
样例输出
10
样例解释
划分成$ [9,6],[1,8,8]$的权值最大
题目分析
解法类似于动态规划。
对于每个区间,答案选择可以看作:分别选择两个数最大值a和最小值b,然后答案加a减b。假设\(dp[i][-1,0,1]\)表示第\(i\)个数字的三种状态的最优解(表示截止到第\(i\)个数字,多了一个a,不多不少,多了一个b),对于每个数,满足这三种状态转移
\[\left\{
\begin{array}{**lr**}
dp[i][0]=&max(dp[i-1][-1]+a[i],&dp[i-1][1]-a[i]&)
\\
dp[i][-1]=&max(dp[i-1][0]-a[i],&dp[i][-1]&)
\\
dp[i][1]=&max(dp[i-1][0]+a[i],&dp[i][1]&)
\end{array}
\right.
\]
事实上用不到\(dp\)数组去存储状态,直接改成三个参数即可\((mx,mn,ans)\)
AC code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+7;
const ll inf = (1ll<<31);
ll ans, a[N];
int main() {
int n;
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++) {
scanf("%lld",&a[i]);
}
ll mx = -inf,mn = -inf;
//维护选正,维护选负
for(int i = 1 ; i <= n ; i++) {
mx = max( {ans+a[i], mx});
mn = max( {ans-a[i], mn});
ans = max( {mx-a[i], mn+a[i],0ll});
}
printf("%lld",ans);
}

浙公网安备 33010602011771号