CF187E Heaven Tour

题意

给定 \(n\) 个点,初始在 \(s\) 点,求走遍所有点的最小移动距离,以及方案,需要向左走恰好 \(l\) 次。

\(n \le 10 ^ 5\)

Sol

难点在于想到枚举终点。

钦定当前若终点在起点右边,那么最优走法就是先向左走到底,然后向右走到底,然后最后再走到终点。

其中中间重复走的段,显然可以发现每一段至多被多走一次,用来多一个 \(l\) 少一个 \(r\),如果一段走了多次,还不如直接重复走旁边的两段。

对于两边本身就走两次的段,尽量全部走 \(l\),这样可以算出来中间需要多走多少次,注意到每次需要的次数是单调不降的,直接对顶堆维护即可。

求方案略显恶心,复杂度:\(O(n \log n)\)

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <queue>
#include <set>
#include <vector>
#define ll long long
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(ll x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

const int N = 1e5 + 5;

namespace Hth {

priority_queue <int> q1;
priority_queue <int, vector <int>, greater <int> > q2;

ll ans;

void insert(int x) { q2.push(x); }

int resize(int k) {
    while (q1.size() > k)
        ans -= q1.top(), q2.push(q1.top()), q1.pop();
    while (q1.size() < k && q2.size())
        ans += q2.top(), q1.push(q2.top()), q2.pop();
    return q1.size() == k;
}

void init() {
    while (q1.size()) q1.pop();
    while (q2.size()) q2.pop();
    ans = 0;
}

} //Hth

array <int, N> s;

vector <ll> solve(int n, int m, int k) {
    Hth::init();
    ll ans = 0, res = 2e18;
    for (int i = k + 1; i <= n; i++) {
        ll _res = 2e18;
        if (k - 1 + n - i >= m)
            _res = 2 * s[n] - s[i] + s[k];
        else if (Hth::resize(m - k - n + i + 1))
            _res = 2 * s[n] - s[i] + s[k] + 2ll * Hth::ans;
        /* if (i == 10) */
            /* cerr << m - k - n + i + 1 << " " << Hth::ans << " " << _res << "@@@@" << endl; */
        if (_res < res) res = _res, ans = i;
        if (i - 1 > k) Hth::insert(s[i] - s[i - 1]);
    }
    if (!ans) return vector <ll>(1, res);
    Hth::init();
    for (int i = k + 2; i < ans; i++)
        Hth::insert(s[i] - s[i - 1]);
    Hth::resize(m - k - n + ans + 1);
    /* cerr << m - k - n + ans + 1 << "@" << endl; */
    vector <ll> isl; multiset <int> req;
    isl.push_back(res);
    while (Hth::q1.size())
        req.insert(Hth::q1.top()), Hth::q1.pop();
    int tp0 = 0;
    for (int i = k - 1; i >= 2; i--)
        if (m > (k != 1) + (ans != n)) isl.push_back(i), m--, tp0++;
    if (k != 1) isl.push_back(1), m--;
    for (int i = 2; i <= k - tp0 - 1; i++)
        isl.push_back(i);
    set <int> tp;
    for (int i = k + 1; i < ans - 1; i++)
        if (i + 1 != ans && req.find(s[i + 1] - s[i]) != req.end() && m > (ans != n))
            tp.insert(i), req.erase(req.find(s[i + 1] - s[i])), m--;
    /* for (auto p : tp) */
        /* cerr << p << "@" << endl; */
    for (int i = k + 1; i <= ans - 1; i++) {
        /* if (i + 1 != ans && m > 1 && req.find(s[i + 1] - s[i]) != req.end()) */
            /* isl.push_back(i + 1), isl.push_back(i), m--, req.erase(req.find(s[i + 1] - s[i])), i += 2; */
        /* else */
            /* isl.push_back(i); */
        int lst = 0;
        while (tp.find(i + lst) != tp.end()) lst++;
        if (!lst) isl.push_back(i);
        else {
            for (int j = lst + i; j >= i; j--)
                isl.push_back(j);
            i += lst;
            /* isl.push_back(-1); */
        }
    }
    for (int i = ans + 1; i <= ans + (n - ans - 1) - (m - (ans != n)); i++)
        isl.push_back(i);
    if (ans != n) isl.push_back(n);
    for (int i = n - 1; i >= n - (m - (ans != n)); i--)
        isl.push_back(i);
    isl.push_back(ans);
    return isl;
}

bool _edmer;
int main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
    int n = read(), m = read(), k = read();
    for (int i = 1; i <= n; i++) s[i] = read();
    if (m == 0) {
        if (k != 1) return puts("-1"), 0;
        write(s[n] - s[1]), puts("");
        for (int i = 2; i <= n; i++)
            write(i), putchar(32);
        return puts(""), 0;
    }
    if (m == n - 1) {
        if (k != n) return puts("-1"), 0;
        write(s[n] - s[1]), puts("");
        for (int i = n - 1; i; i--)
            write(i), putchar(32);
        return puts(""), 0;
    }
    vector <ll> tp1 = solve(n, m, k);
    m = n - 1 - m, k = n - k + 1;
    for (int i = 1; i <= n; i++)
        s[i] = s[n] - s[i];
    reverse(s.begin() + 1, s.begin() + 1 + n);
    /* for (int i = 1; i <= n; i++) */
        /* cerr << s[i] << " "; */
    /* cerr << endl; */
    vector <ll> tp2 = solve(n, m, k);
    if (tp1.front() < tp2.front()) {
        write(tp1.front()), puts("");
        tp1.erase(tp1.begin());
        for (auto p : tp1)
            write(p), putchar(32);
        puts("");
    }
    else {
        write(tp2.front()), puts("");
        tp2.erase(tp2.begin());
        for (auto p : tp2)
            write(n - p + 1), putchar(32);
            /* cerr << p << " "; */
        puts("");
    }
    /* cerr << tp.front() << endl; */
    /* for (auto k : tp) */
        /* cerr << k << " "; */
    /* cerr << endl; */
    return 0;
}
posted @ 2024-11-18 19:41  cxqghzj  阅读(8)  评论(0编辑  收藏  举报