[Codeforces 484D] Kindergarten (DP + 树状数组优化)

Codeforces - 484D

给定一个长度为 N 的数列,可以将连续的一段分成一组
每组的价值为组内最大值减最小值,数列的价值为所有组的价值和
问整个数列的价值的最大值


很容易想到一个 (N2) 的 暴力DP
然后有一个性质,就是每组的最大值最小值一定在边界上
容易证明,如果最值不再边界上,可以向内缩小这个组
把剩余的值让出来给其他组,结果一定不会更劣

然后暴力DP的思路就是 dp[i]=maxi1j=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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值