0913考试T2

0913考试T2

​ 题目大意:给出一个长度为𝑛的数组𝐴,你每次需要选出一个长度大于1的区间[𝑙,𝑟]并删掉它,代价是左右端点的元素之差的绝对值|𝐴𝑙−𝐴𝑟|,之后再将左右两个数组接起来构成一个新的数组。你的任务是要求出删除整个数组的最小代价和。

​ 数据结构优化DP。

​ 设\(f[i]\)为删除区间\([1, i]\)的最小值,那么转移方程很好想:\(f[i] = min(f[j - 1]) + |A_i - A_j|\)

​ 考虑怎么优化。

​ 可以发现方程可以转换一下形式:\(f[i] = min(f[j - 1] - A_j) + A_i\)

\(f[i] = min(f[j - 1] + A_j) - A_i\)

​ 于是我们可以用权值线段树维护\(f[j - 1] - A_j,f[j - 1] + A_j\)的最小值。

#include <bits/stdc++.h>

#define ls(o) (o << 1)
#define rs(o) (o << 1 | 1)
#define mid ((l + r) >> 1)

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1e6 + 5, inf = 1e6;
const long long maxn = 1e16;
int n, cnt;
int a[N], b[N], c[N], lg[N], Max[N][21], Min[N][21];
long long f[N];
struct tree { long long Min1, Min2; } t[N << 2];

void build(int o, int l, int r) {
    t[o].Min1 = t[o].Min2 = maxn;
    if(l == r) return ;
    build(ls(o), l, mid); build(rs(o), mid + 1, r);
}

void up(int o) {
    t[o].Min1 = min(t[ls(o)].Min1, t[rs(o)].Min1);
    t[o].Min2 = min(t[ls(o)].Min2, t[rs(o)].Min2);
}

void insert(int o, int l, int r, int x, long long val1, long long val2) {
    if(l == r) { t[o].Min1 = min(t[o].Min1, val1); t[o].Min2 = min(t[o].Min2, val2); return ; }
    if(x <= mid) insert(ls(o), l, mid, x, val1, val2);
    if(x > mid) insert(rs(o), mid + 1, r, x, val1, val2);
    up(o);
}

long long query_Min1(int o, int l, int r, int x, int y) {
    if(x <= l && y >= r) { return t[o].Min1; }
    long long res = maxn;
    if(x <= mid) res = min(res, query_Min1(ls(o), l, mid, x, y));
    if(y > mid) res = min(res, query_Min1(rs(o), mid + 1, r, x, y));
    return res;
}

long long query_Min2(int o, int l, int r, int x, int y) {
    if(x <= l && y >= r) { return t[o].Min2; }
    long long res = maxn;
    if(x <= mid) res = min(res, query_Min2(ls(o), l, mid, x, y));
    if(y > mid) res = min(res, query_Min2(rs(o), mid + 1, r, x, y));
    return res;
}

int main() {

    // freopen("remove.in","r",stdin); freopen("remove.out","w",stdout);

    n = read();
    for(int i = 1;i <= n; i++) b[i] = a[i] = c[i] = read();
    sort(b + 1, b + n + 1);
    int cnt = unique(b + 1, b + n + 1) - b - 1;
    for(int i = 1;i <= n; i++) a[i] = lower_bound(b + 1, b + cnt + 1, a[i]) - b;

    build(1, 1, inf);
    f[1] = maxn;

    for(int i = 2;i <= n; i++) {
        insert(1, 1, inf, a[i - 1], f[i - 2] - c[i - 1], f[i - 2] + c[i - 1]);
        long long tmp1 = query_Min1(1, 1, inf, 1, a[i]); 
        long long tmp2 = query_Min2(1, 1, inf, a[i] + 1, inf);
        f[i] = min(tmp1 + c[i], tmp2 - c[i]);
    }
    printf("%lld", f[n]);

    fclose(stdin); fclose(stdout);
    return 0;
}

posted @ 2020-09-14 07:30  C锥  阅读(110)  评论(0编辑  收藏  举报