代码源每日一题 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);
}
posted @ 2022-04-07 23:50  seekerHeron  阅读(236)  评论(0)    收藏  举报