Luogu[P3620] Data Backup

Greedy God

First we find an obvious greedy strategy, connecting two adjacent office buildings is always better.

So this question becomes a bunch of points on the number line. It is necessary to select k intervals that are not adjacent to each other, so that the length of the interval is the smallest.

For 10000 data, we can use DP to solve,

f[i][j] represents the minimum distance between j-to-points that have been formed considering the first i points, and num[i] represents the coordinates of the i-th point.

If this point does not form a pair with other points, then f[i][j]=f[i-1][j].

Otherwise, this point can only form a pair with the previous point, f[i][j]=f[i-2][j-1]+num[i]-num[i-1].

f[i][j]=min(f[i-1][j],f[i-2][j-1]+num[i]-num[i-1]);

The time complexity is O(nk), which can be optimized for rolling arrays.

For all data, we have a very strange greed

There is a very subtle transformation here. Assuming that there are abcde5 adjacent points (a<b<c<d<e) on the original n points, after we differentiate it, there are four values ​​of ab,bc,cd,de.

Assuming that bc is the smallest one, we greedily select bc, and then delete it after adding the answer. After that, we take out the ab and cd adjacent to bc at the same time. After all three values ​​are deleted, a new value is synthesized, this value = ab+cd-bc. Then if we select this ab+cd-bc again through the greedy principle and add it to the answer, then the -bc in it will be offset with the bc selected at the beginning, which is equivalent to the fact that we chose ab+cd twice, which is the same as bc. two adjacent sections. Each selection will increase the number of selected segments by 1, so the ans after selecting k times is the optimal solution, which is similar to the backflow operation of network flow

We need to maintain the predecessor and successor of each element with a linked list, and we need to maintain a heap that can delete any element (not just the root element),

There are two operations here. If the maintained value is relatively small, you can maintain a bool array to mark the deleted element. If the maintained element is large, we need to maintain a deletion heap. Every time you ask, compare the deletion heap with

deyuansu

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define ll long long
using namespace std;
const int MAXN = 100005;
int init() {
    int rv = 0, fh = 1;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') fh = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        rv = (rv<<1) + (rv<<3) + c - '0';
        c = getchar();
    }
    return fh * rv;
}
int n, k, loc[MAXN], num[MAXN], pre[MAXN], nxt[MAXN];
struct node {
    int wei, id;
    bool operator < (const node & b) const{
        return b.wei < wei;
    }
};
priority_queue<node> hea;
bool del[MAXN];
ll ans;
int main() {
    n = init(); k = init();
    for(int i = 1; i <= n; i++) {
        loc[i] = init();
        if(i >= 2) {
            num[i - 1] = loc[i] - loc[i - 1];
            hea.push((node){num[i - 1], i - 1});
        }
    }
    for(int i = 1; i <= n; i++) {
        pre[i] = i - 1; nxt[i] = i + 1;
    }
    nxt[0] = 1; nxt[n] = 0;
    num[0] = num[n] = 0x3f3f3f3f;
    for(int i = 1; i <= k; i++) {
        while(del[hea.top().id]) hea.pop();
        ans += hea.top().wei;int x = hea.top().id; hea.pop();
        int l = pre[x], r = nxt[x];
        del[l] = del[r] = 1;
        hea.push((node){num[x] = num[l] + num[r] - num[x], x});
        pre[x] = pre[l]; nxt[x] = nxt[r];
        pre[nxt[r]] = x; nxt[pre[l]] = x;
    }
    cout << ans << endl;
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325292569&siteId=291194637