Codeforces - 484D
给定一个长度为 N 的数列,可以将连续的一段分成一组
每组的价值为组内最大值减最小值,数列的价值为所有组的价值和
问整个数列的价值的最大值
很容易想到一个
(N2)
的 暴力DP
然后有一个性质,就是每组的最大值最小值一定在边界上
容易证明,如果最值不再边界上,可以向内缩小这个组
把剩余的值让出来给其他组,结果一定不会更劣
然后暴力DP的思路就是
dp[i]=maxi−1j=1(dp[j])
用 BIT 优化一下,存一下
dp[i]+in[i+1]
和
dp[i]−in[i+1]
然后 DP 的时候在 BIT 里找最优值,复杂度就变为
(NlogN)
了
#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <string>
#include <complex>
using namespace std;
typedef pair<int,int> Pii;
typedef long long LL;
typedef unsigned long long ULL;
typedef double DBL;
typedef long double LDBL;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define SQR(a) ((a)*(a))
#define PCUT puts("\n----------")
const int maxn=1e6+10;
struct BIT
{
int siz;
LL bit[maxn];
void init(int _siz){siz=_siz; MST(bit,0x80);}
void update(int p, LL x)
{
for(int i=p; i<=siz; i+=i&-i) bit[i] = max(bit[i], x);
}
LL query(int p)
{
LL res=0x8080808080808080;
for(int i=p; i>0; i-=i&-i) res = max(res, bit[i]);
return res;
}
void rupdate(int p, LL x){update(siz-p+1, x);}
LL rquery(int p){return query(siz-p+1);}
};
int N, in[maxn], id[maxn], lst[maxn];
LL dp[maxn];
BIT bit[2];
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
while(~scanf("%d", &N))
{
bit[0].init(N); bit[1].init(N);
for(int i=1; i<=N; i++) scanf("%d", &in[i]), lst[i]=in[i];
sort(lst+1, lst+1+N);
int tot = unique(lst+1, lst+1+N) - (lst+1);
for(int i=1; i<=N; i++) id[i] = lower_bound(lst+1, lst+1+N, in[i])-lst;
for(int i=1; i<=N; i++)
{
bit[0].rupdate(id[i], dp[i-1]+in[i]);
bit[1].update(id[i], dp[i-1]-in[i]);
dp[i] = max(bit[0].rquery(id[i])-in[i], bit[1].query(id[i])+in[i]);
// printf("%d: %lld %lld\n", i, bit[0].rquery(id[i]), bit[1].query(id[i]));
// printf("%lld\n", dp[i]);
}
printf("%lld\n", dp[N]);
}
return 0;
}