1. 程式人生 > >[luogu3620][APIO/CTSC 2007]數據備份

[luogu3620][APIO/CTSC 2007]數據備份

簡單 好的 bits pri alt 分析 mat 技術 因此

題目描述

你在一家 IT 公司為大型寫字樓或辦公樓(offices)的計算機數據做備份。然而數據備份的工作是枯燥乏味的,因此你想設計一個系統讓不同的辦公樓彼此之間互相備份,而你則坐在家中盡享計算機遊戲的樂趣。
已知辦公樓都位於同一條街上。你決定給這些辦公樓配對(兩個一組)。每一對辦公樓可以通過在這兩個建築物之間鋪設網絡電纜使得它們可以互相備份。
然而,網絡電纜的費用很高。當地電信公司僅能為你提供 K 條網絡電纜,這意味著你僅能為 K 對辦公樓(或總計 2K 個辦公樓)安排備份。任一個辦公樓都屬於唯一的配對組(換句話說,這 2K 個辦公樓一定是相異的)。
此外,電信公司需按網絡電纜的長度(公裏數)收費。因而,你需要選擇這 K對辦公樓使得電纜的總長度盡可能短。換句話說,你需要選擇這 K 對辦公樓,使得每一對辦公樓之間的距離之和(總距離)盡可能小。

下面給出一個示例,假定你有 5 個客戶,其辦公樓都在一條街上,如下圖所示。這 5 個辦公樓分別位於距離大街起點 1km, 3km, 4km, 6km 和 12km 處。電信公司僅為你提供 K=2 條電纜。
技術分享圖片
上例中最好的配對方案是將第 1 個和第 2 個辦公樓相連,第 3 個和第 4 個辦公樓相連。這樣可按要求使用 K=2 條電纜。第 1 條電纜的長度是 3km―1km = 2km,第 2 條電纜的長度是 6km―4km = 2 km。這種配對方案需要總長 4km 的網絡電纜,滿足距離之和最小的要求。

分析

題目大意
給你n個數,兩個數分成一組,一共分成k組,使得相差的和最小。
顯然,一組的數一定是相鄰的,那麽考慮最簡單最不對的暴力就是找出所有的差然後排序取前k個。

明顯不對,那麽我們就先差分求出兩個數之間的差,然後全部放到一個優先隊列中,因為我們只能有k個。(慕容寶寶大佬好巨啊),慕容寶寶大佬說什麽反悔機制???簡單的說就是因為不能取相鄰的,那麽相鄰3個的差分都不能拿,那麽我們就將這三個打一個包。表示的是一開始貪心時我們選擇的是中間這一個。
之後再優先隊列查詢到這個不需要的時候,我們就將這個,換掉,也就是\(a[left]+a[right]-a[mid]\),也就是將兩邊的加回來,將這個點刪除。
刪除操作問題,我們可以用雙向鏈表來維護就可以了。

ac代碼

#include <bits/stdc++.h>
#define ll long long
#define ms(a, b) memset(a, b, sizeof(a))
#define inf 0x3f3f3f3f
#define N 100005
using namespace std;
template <typename T>
inline void read(T &x) {
    x = 0; T fl = 1;
    char ch = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-') fl = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    x *= fl;
};
struct node {
    int id, val;
    node(int id, int val): id(id), val(val){}
    bool operator <(const node &rhs) const {;
        return val > rhs.val;
    }
};
int f[N], a[N], nxt[N], lst[N];
int n, k;
priority_queue<node>q;
ll ans = 0;
int main() {
    read(n); read(k);
    for (int i = 1; i <= n; i ++) {
        read(a[i]);
    }
    for (int i = 1; i < n; i ++) {
        f[i] = a[i + 1] - a[i];
        nxt[i] = i + 1;
        lst[i] = i - 1;
    }
    nxt[n - 1] = 0;
    for (int i = 1; i < n; i ++) q.push(node(i, f[i]));
    for (int i = 1; i <= k; i ++) {
        node nw = q.top();
        q.pop();
        if (nw.val != f[nw.id]) {
            ++ k;
            continue;
        }
        ans += nw.val;
        int left = lst[nw.id], right = nxt[nw.id];
        nxt[nw.id] = nxt[right]; 
        lst[nxt[nw.id]] = nw.id;
        lst[nw.id] = lst[left]; 
        nxt[lst[nw.id]] = nw.id;
        f[nw.id] = (left && right) ? min(inf, f[left] + f[right] - f[nw.id]): inf;
        f[left] = f[right] = inf;
        q.push(node(nw.id, f[nw.id]));
    }
    printf("%lld\n", ans);
    return 0;
}

[luogu3620][APIO/CTSC 2007]數據備份